MySQLUserData.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  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 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. using (IDbCommand result = dbm.Manager.Query(
  162. "SELECT * FROM " + m_usersTableName + " WHERE username = ?first AND lastname = ?second", param))
  163. {
  164. using (IDataReader reader = result.ExecuteReader())
  165. {
  166. UserProfileData row = dbm.Manager.readUserRow(reader);
  167. return row;
  168. }
  169. }
  170. }
  171. catch (Exception e)
  172. {
  173. dbm.Manager.Reconnect();
  174. m_log.Error(e.Message, e);
  175. return null;
  176. }
  177. finally
  178. {
  179. dbm.Release();
  180. }
  181. }
  182. #region User Friends List Data
  183. public override void AddNewUserFriend(UUID friendlistowner, UUID friend, uint perms)
  184. {
  185. int dtvalue = Util.UnixTimeSinceEpoch();
  186. Dictionary<string, object> param = new Dictionary<string, object>();
  187. param["?ownerID"] = friendlistowner.ToString();
  188. param["?friendID"] = friend.ToString();
  189. param["?friendPerms"] = perms.ToString();
  190. param["?datetimestamp"] = dtvalue.ToString();
  191. MySQLSuperManager dbm = GetLockedConnection("AddNewUserFriend");
  192. try
  193. {
  194. using (IDbCommand adder = dbm.Manager.Query(
  195. "INSERT INTO `" + m_userFriendsTableName + "` " +
  196. "(`ownerID`,`friendID`,`friendPerms`,`datetimestamp`) " +
  197. "VALUES " +
  198. "(?ownerID,?friendID,?friendPerms,?datetimestamp)",
  199. param))
  200. {
  201. adder.ExecuteNonQuery();
  202. }
  203. using (IDbCommand adder = dbm.Manager.Query(
  204. "INSERT INTO `" + m_userFriendsTableName + "` " +
  205. "(`ownerID`,`friendID`,`friendPerms`,`datetimestamp`) " +
  206. "VALUES " +
  207. "(?friendID,?ownerID,?friendPerms,?datetimestamp)",
  208. param))
  209. {
  210. adder.ExecuteNonQuery();
  211. }
  212. }
  213. catch (Exception e)
  214. {
  215. dbm.Manager.Reconnect();
  216. m_log.Error(e.Message, e);
  217. return;
  218. }
  219. finally
  220. {
  221. dbm.Release();
  222. }
  223. }
  224. public override void RemoveUserFriend(UUID friendlistowner, UUID friend)
  225. {
  226. Dictionary<string, object> param = new Dictionary<string, object>();
  227. param["?ownerID"] = friendlistowner.ToString();
  228. param["?friendID"] = friend.ToString();
  229. MySQLSuperManager dbm = GetLockedConnection("RemoveUserFriend");
  230. try
  231. {
  232. using (IDbCommand updater = dbm.Manager.Query(
  233. "delete from " + m_userFriendsTableName + " where ownerID = ?ownerID and friendID = ?friendID",
  234. param))
  235. {
  236. updater.ExecuteNonQuery();
  237. }
  238. using (IDbCommand updater = dbm.Manager.Query(
  239. "delete from " + m_userFriendsTableName + " where ownerID = ?friendID and friendID = ?ownerID",
  240. param))
  241. {
  242. updater.ExecuteNonQuery();
  243. }
  244. }
  245. catch (Exception e)
  246. {
  247. dbm.Manager.Reconnect();
  248. m_log.Error(e.Message, e);
  249. return;
  250. }
  251. finally
  252. {
  253. dbm.Release();
  254. }
  255. }
  256. public override void UpdateUserFriendPerms(UUID friendlistowner, UUID friend, uint perms)
  257. {
  258. Dictionary<string, object> param = new Dictionary<string, object>();
  259. param["?ownerID"] = friendlistowner.ToString();
  260. param["?friendID"] = friend.ToString();
  261. param["?friendPerms"] = perms.ToString();
  262. MySQLSuperManager dbm = GetLockedConnection("UpdateUserFriendPerms");
  263. try
  264. {
  265. using (IDbCommand updater = dbm.Manager.Query(
  266. "update " + m_userFriendsTableName +
  267. " SET friendPerms = ?friendPerms " +
  268. "where ownerID = ?ownerID and friendID = ?friendID",
  269. param))
  270. {
  271. updater.ExecuteNonQuery();
  272. }
  273. }
  274. catch (Exception e)
  275. {
  276. dbm.Manager.Reconnect();
  277. m_log.Error(e.Message, e);
  278. return;
  279. }
  280. finally
  281. {
  282. dbm.Release();
  283. }
  284. }
  285. public override List<FriendListItem> GetUserFriendList(UUID friendlistowner)
  286. {
  287. List<FriendListItem> Lfli = new List<FriendListItem>();
  288. Dictionary<string, object> param = new Dictionary<string, object>();
  289. param["?ownerID"] = friendlistowner.ToString();
  290. MySQLSuperManager dbm = GetLockedConnection("GetUserFriendList");
  291. try
  292. {
  293. //Left Join userfriends to itself
  294. using (IDbCommand result = dbm.Manager.Query(
  295. "select a.ownerID,a.friendID,a.friendPerms,b.friendPerms as ownerperms from " +
  296. m_userFriendsTableName + " as a, " + m_userFriendsTableName + " as b" +
  297. " where a.ownerID = ?ownerID and b.ownerID = a.friendID and b.friendID = a.ownerID",
  298. param))
  299. {
  300. using (IDataReader reader = result.ExecuteReader())
  301. {
  302. while (reader.Read())
  303. {
  304. FriendListItem fli = new FriendListItem();
  305. fli.FriendListOwner = new UUID((string)reader["ownerID"]);
  306. fli.Friend = new UUID((string)reader["friendID"]);
  307. fli.FriendPerms = (uint)Convert.ToInt32(reader["friendPerms"]);
  308. // This is not a real column in the database table, it's a joined column from the opposite record
  309. fli.FriendListOwnerPerms = (uint)Convert.ToInt32(reader["ownerperms"]);
  310. Lfli.Add(fli);
  311. }
  312. }
  313. }
  314. }
  315. catch (Exception e)
  316. {
  317. dbm.Manager.Reconnect();
  318. m_log.Error(e.Message, e);
  319. return Lfli;
  320. }
  321. finally
  322. {
  323. dbm.Release();
  324. }
  325. return Lfli;
  326. }
  327. override public Dictionary<UUID, FriendRegionInfo> GetFriendRegionInfos (List<UUID> uuids)
  328. {
  329. MySQLSuperManager dbm = GetLockedConnection("GetFriendRegionInfos");
  330. Dictionary<UUID, FriendRegionInfo> infos = new Dictionary<UUID,FriendRegionInfo>();
  331. try
  332. {
  333. foreach (UUID uuid in uuids)
  334. {
  335. Dictionary<string, object> param = new Dictionary<string, object>();
  336. param["?uuid"] = uuid.ToString();
  337. using (IDbCommand result = dbm.Manager.Query("select agentOnline,currentHandle from " + m_agentsTableName +
  338. " where UUID = ?uuid", param))
  339. {
  340. using (IDataReader reader = result.ExecuteReader())
  341. {
  342. while (reader.Read())
  343. {
  344. FriendRegionInfo fri = new FriendRegionInfo();
  345. fri.isOnline = (sbyte)reader["agentOnline"] != 0;
  346. fri.regionHandle = (ulong)reader["currentHandle"];
  347. infos[uuid] = fri;
  348. }
  349. }
  350. }
  351. }
  352. }
  353. catch (Exception e)
  354. {
  355. m_log.Warn("[MYSQL]: Got exception on trying to find friends regions:", e);
  356. dbm.Manager.Reconnect();
  357. m_log.Error(e.Message, e);
  358. }
  359. finally
  360. {
  361. dbm.Release();
  362. }
  363. return infos;
  364. }
  365. #endregion
  366. public override List<AvatarPickerAvatar> GeneratePickerResults(UUID queryID, string query)
  367. {
  368. List<AvatarPickerAvatar> returnlist = new List<AvatarPickerAvatar>();
  369. Regex objAlphaNumericPattern = new Regex("[^a-zA-Z0-9]");
  370. string[] querysplit;
  371. querysplit = query.Split(' ');
  372. if (querysplit.Length > 1 && querysplit[1].Trim() != String.Empty)
  373. {
  374. Dictionary<string, object> param = new Dictionary<string, object>();
  375. param["?first"] = objAlphaNumericPattern.Replace(querysplit[0], String.Empty) + "%";
  376. param["?second"] = objAlphaNumericPattern.Replace(querysplit[1], String.Empty) + "%";
  377. MySQLSuperManager dbm = GetLockedConnection("GeneratePickerResults");
  378. try
  379. {
  380. using (IDbCommand result = dbm.Manager.Query(
  381. "SELECT UUID,username,lastname FROM " + m_usersTableName +
  382. " WHERE username like ?first AND lastname like ?second LIMIT 100",
  383. param))
  384. {
  385. using (IDataReader reader = result.ExecuteReader())
  386. {
  387. while (reader.Read())
  388. {
  389. AvatarPickerAvatar user = new AvatarPickerAvatar();
  390. user.AvatarID = new UUID((string)reader["UUID"]);
  391. user.firstName = (string)reader["username"];
  392. user.lastName = (string)reader["lastname"];
  393. returnlist.Add(user);
  394. }
  395. }
  396. }
  397. }
  398. catch (Exception e)
  399. {
  400. dbm.Manager.Reconnect();
  401. m_log.Error(e.Message, e);
  402. return returnlist;
  403. }
  404. finally
  405. {
  406. dbm.Release();
  407. }
  408. }
  409. else
  410. {
  411. MySQLSuperManager dbm = GetLockedConnection("GeneratePickerResults");
  412. try
  413. {
  414. Dictionary<string, object> param = new Dictionary<string, object>();
  415. param["?first"] = objAlphaNumericPattern.Replace(querysplit[0], String.Empty) + "%";
  416. using (IDbCommand result = dbm.Manager.Query(
  417. "SELECT UUID,username,lastname FROM " + m_usersTableName +
  418. " WHERE username like ?first OR lastname like ?first LIMIT 100",
  419. param))
  420. {
  421. using (IDataReader reader = result.ExecuteReader())
  422. {
  423. while (reader.Read())
  424. {
  425. AvatarPickerAvatar user = new AvatarPickerAvatar();
  426. user.AvatarID = new UUID((string)reader["UUID"]);
  427. user.firstName = (string)reader["username"];
  428. user.lastName = (string)reader["lastname"];
  429. returnlist.Add(user);
  430. }
  431. }
  432. }
  433. }
  434. catch (Exception e)
  435. {
  436. dbm.Manager.Reconnect();
  437. m_log.Error(e.Message, e);
  438. return returnlist;
  439. }
  440. finally
  441. {
  442. dbm.Release();
  443. }
  444. }
  445. return returnlist;
  446. }
  447. /// <summary>
  448. /// See IUserDataPlugin
  449. /// </summary>
  450. /// <param name="uuid">User UUID</param>
  451. /// <returns>User profile data</returns>
  452. public override UserProfileData GetUserByUUID(UUID uuid)
  453. {
  454. MySQLSuperManager dbm = GetLockedConnection("GetUserByUUID");
  455. try
  456. {
  457. Dictionary<string, object> param = new Dictionary<string, object>();
  458. param["?uuid"] = uuid.ToString();
  459. using (IDbCommand result = dbm.Manager.Query("SELECT * FROM " + m_usersTableName + " WHERE UUID = ?uuid", param))
  460. {
  461. using (IDataReader reader = result.ExecuteReader())
  462. {
  463. UserProfileData row = dbm.Manager.readUserRow(reader);
  464. return row;
  465. }
  466. }
  467. }
  468. catch (Exception e)
  469. {
  470. dbm.Manager.Reconnect();
  471. m_log.Error(e.Message, e);
  472. return null;
  473. }
  474. finally
  475. {
  476. dbm.Release();
  477. }
  478. }
  479. /// <summary>
  480. /// Returns a user session searching by name
  481. /// </summary>
  482. /// <param name="name">The account name : "Username Lastname"</param>
  483. /// <returns>The users session</returns>
  484. public override UserAgentData GetAgentByName(string name)
  485. {
  486. return GetAgentByName(name.Split(' ')[0], name.Split(' ')[1]);
  487. }
  488. /// <summary>
  489. /// Returns a user session by account name
  490. /// </summary>
  491. /// <param name="user">First part of the users account name</param>
  492. /// <param name="last">Second part of the users account name</param>
  493. /// <returns>The users session</returns>
  494. public override UserAgentData GetAgentByName(string user, string last)
  495. {
  496. UserProfileData profile = GetUserByName(user, last);
  497. return GetAgentByUUID(profile.ID);
  498. }
  499. /// <summary>
  500. /// </summary>
  501. /// <param name="AgentID"></param>
  502. /// <param name="WebLoginKey"></param>
  503. /// <remarks>is it still used ?</remarks>
  504. public override void StoreWebLoginKey(UUID AgentID, UUID WebLoginKey)
  505. {
  506. Dictionary<string, string> param = new Dictionary<string, string>();
  507. param["?UUID"] = AgentID.ToString();
  508. param["?webLoginKey"] = WebLoginKey.ToString();
  509. MySQLSuperManager dbm = GetLockedConnection("StoreWebLoginKey");
  510. try
  511. {
  512. dbm.Manager.ExecuteParameterizedSql(
  513. "update " + m_usersTableName + " SET webLoginKey = ?webLoginKey " +
  514. "where UUID = ?UUID",
  515. param);
  516. }
  517. catch (Exception e)
  518. {
  519. dbm.Manager.Reconnect();
  520. m_log.Error(e.Message, e);
  521. return;
  522. }
  523. finally
  524. {
  525. dbm.Release();
  526. }
  527. }
  528. /// <summary>
  529. /// Returns an agent session by account UUID
  530. /// </summary>
  531. /// <param name="uuid">The accounts UUID</param>
  532. /// <returns>The users session</returns>
  533. public override UserAgentData GetAgentByUUID(UUID uuid)
  534. {
  535. MySQLSuperManager dbm = GetLockedConnection("GetAgentByUUID");
  536. try
  537. {
  538. Dictionary<string, object> param = new Dictionary<string, object>();
  539. param["?uuid"] = uuid.ToString();
  540. using (IDbCommand result = dbm.Manager.Query("SELECT * FROM " + m_agentsTableName + " WHERE UUID = ?uuid", param))
  541. {
  542. using (IDataReader reader = result.ExecuteReader())
  543. {
  544. UserAgentData row = dbm.Manager.readAgentRow(reader);
  545. return row;
  546. }
  547. }
  548. }
  549. catch (Exception e)
  550. {
  551. dbm.Manager.Reconnect();
  552. m_log.Error(e.Message, e);
  553. return null;
  554. }
  555. finally
  556. {
  557. dbm.Release();
  558. }
  559. }
  560. /// <summary>
  561. /// Creates a new users profile
  562. /// </summary>
  563. /// <param name="user">The user profile to create</param>
  564. public override void AddNewUserProfile(UserProfileData user)
  565. {
  566. UUID zero = UUID.Zero;
  567. if (user.ID == zero)
  568. {
  569. return;
  570. }
  571. MySQLSuperManager dbm = GetLockedConnection("AddNewUserProfile");
  572. try
  573. {
  574. dbm.Manager.insertUserRow(
  575. user.ID, user.FirstName, user.SurName, user.Email, user.PasswordHash, user.PasswordSalt,
  576. user.HomeRegion, user.HomeRegionID, user.HomeLocation.X, user.HomeLocation.Y,
  577. user.HomeLocation.Z,
  578. user.HomeLookAt.X, user.HomeLookAt.Y, user.HomeLookAt.Z, user.Created,
  579. user.LastLogin, user.UserInventoryURI, user.UserAssetURI,
  580. user.CanDoMask, user.WantDoMask,
  581. user.AboutText, user.FirstLifeAboutText, user.Image,
  582. user.FirstLifeImage, user.WebLoginKey, user.UserFlags, user.GodLevel, user.CustomType, user.Partner);
  583. }
  584. catch (Exception e)
  585. {
  586. dbm.Manager.Reconnect();
  587. m_log.Error(e.Message, e);
  588. }
  589. finally
  590. {
  591. dbm.Release();
  592. }
  593. }
  594. /// <summary>
  595. /// Creates a new agent
  596. /// </summary>
  597. /// <param name="agent">The agent to create</param>
  598. public override void AddNewUserAgent(UserAgentData agent)
  599. {
  600. UUID zero = UUID.Zero;
  601. if (agent.ProfileID == zero || agent.SessionID == zero)
  602. return;
  603. MySQLSuperManager dbm = GetLockedConnection("AddNewUserAgent");
  604. try
  605. {
  606. dbm.Manager.insertAgentRow(agent);
  607. }
  608. catch (Exception e)
  609. {
  610. dbm.Manager.Reconnect();
  611. m_log.Error(e.Message, e);
  612. }
  613. finally
  614. {
  615. dbm.Release();
  616. }
  617. }
  618. /// <summary>
  619. /// Updates a user profile stored in the DB
  620. /// </summary>
  621. /// <param name="user">The profile data to use to update the DB</param>
  622. public override bool UpdateUserProfile(UserProfileData user)
  623. {
  624. MySQLSuperManager dbm = GetLockedConnection("UpdateUserProfile");
  625. try
  626. {
  627. dbm.Manager.updateUserRow(
  628. user.ID, user.FirstName, user.SurName, user.Email, user.PasswordHash, user.PasswordSalt,
  629. user.HomeRegion, user.HomeRegionID, user.HomeLocation.X, user.HomeLocation.Y,
  630. user.HomeLocation.Z, user.HomeLookAt.X,
  631. user.HomeLookAt.Y, user.HomeLookAt.Z, user.Created, user.LastLogin,
  632. user.UserInventoryURI,
  633. user.UserAssetURI, user.CanDoMask, user.WantDoMask, user.AboutText,
  634. user.FirstLifeAboutText, user.Image, user.FirstLifeImage, user.WebLoginKey,
  635. user.UserFlags, user.GodLevel, user.CustomType, user.Partner);
  636. }
  637. finally
  638. {
  639. dbm.Release();
  640. }
  641. return true;
  642. }
  643. /// <summary>
  644. /// Performs a money transfer request between two accounts
  645. /// </summary>
  646. /// <param name="from">The senders account ID</param>
  647. /// <param name="to">The receivers account ID</param>
  648. /// <param name="amount">The amount to transfer</param>
  649. /// <returns>Success?</returns>
  650. public override bool MoneyTransferRequest(UUID from, UUID to, uint amount)
  651. {
  652. return false;
  653. }
  654. /// <summary>
  655. /// Performs an inventory transfer request between two accounts
  656. /// </summary>
  657. /// <remarks>TODO: Move to inventory server</remarks>
  658. /// <param name="from">The senders account ID</param>
  659. /// <param name="to">The receivers account ID</param>
  660. /// <param name="item">The item to transfer</param>
  661. /// <returns>Success?</returns>
  662. public override bool InventoryTransferRequest(UUID from, UUID to, UUID item)
  663. {
  664. return false;
  665. }
  666. /// <summary>
  667. /// Appearance
  668. /// TODO: stubs for now to get us to a compiling state gently
  669. /// override
  670. /// </summary>
  671. public override AvatarAppearance GetUserAppearance(UUID user)
  672. {
  673. MySQLSuperManager dbm = GetLockedConnection("GetUserAppearance");
  674. try
  675. {
  676. Dictionary<string, object> param = new Dictionary<string, object>();
  677. param["?owner"] = user.ToString();
  678. using (IDbCommand result = dbm.Manager.Query("SELECT * FROM " + m_appearanceTableName + " WHERE owner = ?owner", param))
  679. {
  680. using (IDataReader reader = result.ExecuteReader())
  681. {
  682. AvatarAppearance appearance = dbm.Manager.readAppearanceRow(reader);
  683. if (appearance == null)
  684. {
  685. m_log.WarnFormat("[USER DB] No appearance found for user {0}", user.ToString());
  686. return null;
  687. }
  688. else
  689. {
  690. appearance.SetAttachments(GetUserAttachments(user));
  691. return appearance;
  692. }
  693. }
  694. }
  695. }
  696. catch (Exception e)
  697. {
  698. dbm.Manager.Reconnect();
  699. m_log.Error(e.Message, e);
  700. return null;
  701. }
  702. finally
  703. {
  704. dbm.Release();
  705. }
  706. }
  707. /// <summary>
  708. /// Updates an avatar appearence
  709. /// </summary>
  710. /// <param name="user">The user UUID</param>
  711. /// <param name="appearance">The avatar appearance</param>
  712. // override
  713. public override void UpdateUserAppearance(UUID user, AvatarAppearance appearance)
  714. {
  715. MySQLSuperManager dbm = GetLockedConnection("UpdateUserAppearance");
  716. try
  717. {
  718. appearance.Owner = user;
  719. dbm.Manager.insertAppearanceRow(appearance);
  720. UpdateUserAttachments(user, appearance.GetAttachments());
  721. }
  722. catch (Exception e)
  723. {
  724. dbm.Manager.Reconnect();
  725. m_log.Error(e.Message, e);
  726. }
  727. finally
  728. {
  729. dbm.Release();
  730. }
  731. }
  732. /// <summary>
  733. /// Database provider name
  734. /// </summary>
  735. /// <returns>Provider name</returns>
  736. public override string Name
  737. {
  738. get { return "MySQL Userdata Interface"; }
  739. }
  740. /// <summary>
  741. /// Database provider version
  742. /// </summary>
  743. /// <returns>provider version</returns>
  744. public override string Version
  745. {
  746. get { return "0.1"; }
  747. }
  748. public Hashtable GetUserAttachments(UUID agentID)
  749. {
  750. Dictionary<string, object> param = new Dictionary<string, object>();
  751. param["?uuid"] = agentID.ToString();
  752. MySQLSuperManager dbm = GetLockedConnection("GetUserAttachments");
  753. try
  754. {
  755. using (IDbCommand result = dbm.Manager.Query(
  756. "SELECT attachpoint, item, asset from " + m_attachmentsTableName + " WHERE UUID = ?uuid", param))
  757. {
  758. using (IDataReader reader = result.ExecuteReader())
  759. {
  760. Hashtable ret = dbm.Manager.readAttachments(reader);
  761. return ret;
  762. }
  763. }
  764. }
  765. catch (Exception e)
  766. {
  767. dbm.Manager.Reconnect();
  768. m_log.Error(e.Message, e);
  769. return null;
  770. }
  771. finally
  772. {
  773. dbm.Release();
  774. }
  775. }
  776. public void UpdateUserAttachments(UUID agentID, Hashtable data)
  777. {
  778. MySQLSuperManager dbm = GetLockedConnection("UpdateUserAttachments");
  779. try
  780. {
  781. dbm.Manager.writeAttachments(agentID, data);
  782. }
  783. finally
  784. {
  785. dbm.Release();
  786. }
  787. }
  788. public override void ResetAttachments(UUID userID)
  789. {
  790. Dictionary<string, string> param = new Dictionary<string, string>();
  791. param["?uuid"] = userID.ToString();
  792. MySQLSuperManager dbm = GetLockedConnection("ResetAttachments");
  793. try
  794. {
  795. dbm.Manager.ExecuteParameterizedSql(
  796. "UPDATE " + m_attachmentsTableName +
  797. " SET asset = '00000000-0000-0000-0000-000000000000' WHERE UUID = ?uuid",
  798. param);
  799. }
  800. finally
  801. {
  802. dbm.Release();
  803. }
  804. }
  805. public override void LogoutUsers(UUID regionID)
  806. {
  807. Dictionary<string, string> param = new Dictionary<string, string>();
  808. param["?regionID"] = regionID.ToString();
  809. MySQLSuperManager dbm = GetLockedConnection("LogoutUsers");
  810. try
  811. {
  812. dbm.Manager.ExecuteParameterizedSql(
  813. "update " + m_agentsTableName + " SET agentOnline = 0 " +
  814. "where currentRegion = ?regionID",
  815. param);
  816. }
  817. catch (Exception e)
  818. {
  819. dbm.Manager.Reconnect();
  820. m_log.Error(e.Message, e);
  821. return;
  822. }
  823. finally
  824. {
  825. dbm.Release();
  826. }
  827. }
  828. }
  829. }