diff --git a/OpenSim/Framework/Communications/Osp/OspInventoryWrapperPlugin.cs b/OpenSim/Framework/Communications/Osp/OspInventoryWrapperPlugin.cs deleted file mode 100644 index bcd1eee05c..0000000000 --- a/OpenSim/Framework/Communications/Osp/OspInventoryWrapperPlugin.cs +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Collections.Generic; -using OpenSim.Data; -using OpenMetaverse; -using OpenSim.Services.Interfaces; - -namespace OpenSim.Framework.Communications.Osp -{ - /// - /// Wrap other inventory data plugins so that we can perform OSP related post processing for items - /// - public class OspInventoryWrapperPlugin : IInventoryDataPlugin - { - protected IInventoryDataPlugin m_wrappedPlugin; - //protected CommunicationsManager m_commsManager; - protected IUserAccountService m_userAccountService; - - public OspInventoryWrapperPlugin(IInventoryDataPlugin wrappedPlugin, IUserAccountService userService) - { - m_wrappedPlugin = wrappedPlugin; - m_userAccountService = userService; - } - - public string Name { get { return "OspInventoryWrapperPlugin"; } } - public string Version { get { return "0.1"; } } - public void Initialise() {} - public void Initialise(string connect) {} - public void Dispose() {} - - public InventoryItemBase getInventoryItem(UUID item) - { - return PostProcessItem(m_wrappedPlugin.getInventoryItem(item)); - } - - // XXX: Why on earth does this exist as it appears to duplicate getInventoryItem? - public InventoryItemBase queryInventoryItem(UUID item) - { - return PostProcessItem(m_wrappedPlugin.queryInventoryItem(item)); - } - - public List getInventoryInFolder(UUID folderID) - { - List items = m_wrappedPlugin.getInventoryInFolder(folderID); - - foreach (InventoryItemBase item in items) - PostProcessItem(item); - - return items; - } - - public List fetchActiveGestures(UUID avatarID) - { - return m_wrappedPlugin.fetchActiveGestures(avatarID); - - // Presuming that no post processing is needed here as gestures don't refer to creator information (?) - } - - protected InventoryItemBase PostProcessItem(InventoryItemBase item) - { - item.CreatorIdAsUuid = OspResolver.ResolveOspa(item.CreatorId, m_userAccountService); - return item; - } - - public List getFolderHierarchy(UUID parentID) { return m_wrappedPlugin.getFolderHierarchy(parentID); } - public List getUserRootFolders(UUID user) { return m_wrappedPlugin.getUserRootFolders(user); } - public InventoryFolderBase getUserRootFolder(UUID user) { return m_wrappedPlugin.getUserRootFolder(user); } - public List getInventoryFolders(UUID parentID) { return m_wrappedPlugin.getInventoryFolders(parentID); } - public InventoryFolderBase getInventoryFolder(UUID folder) { return m_wrappedPlugin.getInventoryFolder(folder); } - public void addInventoryItem(InventoryItemBase item) { m_wrappedPlugin.addInventoryItem(item); } - public void updateInventoryItem(InventoryItemBase item) { m_wrappedPlugin.updateInventoryItem(item); } - public void deleteInventoryItem(UUID item) { m_wrappedPlugin.deleteInventoryItem(item); } - public InventoryFolderBase queryInventoryFolder(UUID folder) { return m_wrappedPlugin.queryInventoryFolder(folder); } - public void addInventoryFolder(InventoryFolderBase folder) { m_wrappedPlugin.addInventoryFolder(folder); } - public void updateInventoryFolder(InventoryFolderBase folder) { m_wrappedPlugin.updateInventoryFolder(folder); } - public void moveInventoryFolder(InventoryFolderBase folder) { m_wrappedPlugin.moveInventoryFolder(folder); } - public void deleteInventoryFolder(UUID folder) { m_wrappedPlugin.deleteInventoryFolder(folder); } - } -} diff --git a/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs b/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs new file mode 100644 index 0000000000..6e8c2ee173 --- /dev/null +++ b/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs @@ -0,0 +1,99 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; + +using OpenMetaverse; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Framework.Serialization.External +{ + /// + /// Utilities for manipulating external representations of data structures in OpenSim + /// + public class ExternalRepresentationUtils + { + /// + /// Takes a XML representation of a SceneObjectPart and returns another XML representation + /// with creator data added to it. + /// + /// The SceneObjectPart represented in XML2 + /// The URL of the profile service for the creator + /// The service for retrieving user account information + /// The scope of the user account information (Grid ID) + /// The SceneObjectPart represented in XML2 + public static string RewriteSOP(string xml, string profileURL, IUserAccountService userService, UUID scopeID) + { + if (xml == string.Empty || profileURL == string.Empty || userService == null) + return xml; + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + XmlNodeList sops = doc.GetElementsByTagName("SceneObjectPart"); + + foreach (XmlNode sop in sops) + { + UserAccount creator = null; + bool hasCreatorData = false; + XmlNodeList nodes = sop.ChildNodes; + foreach (XmlNode node in nodes) + { + if (node.Name == "CreatorID") + { + UUID uuid = UUID.Zero; + UUID.TryParse(node.InnerText, out uuid); + creator = userService.GetUserAccount(scopeID, uuid); + } + if (node.Name == "CreatorData" && node.InnerText != null && node.InnerText != string.Empty) + hasCreatorData = true; + + //if (node.Name == "OwnerID") + //{ + // UserAccount owner = GetUser(node.InnerText); + // if (owner != null) + // node.InnerText = m_ProfileServiceURL + "/" + node.InnerText + "/" + owner.FirstName + " " + owner.LastName; + //} + } + if (!hasCreatorData && creator != null) + { + XmlElement creatorData = doc.CreateElement("CreatorData"); + creatorData.InnerText = profileURL + "/" + creator.PrincipalID + ";" + creator.FirstName + " " + creator.LastName; + sop.AppendChild(creatorData); + } + } + + using (StringWriter wr = new StringWriter()) + { + doc.Save(wr); + return wr.ToString(); + } + + } + } +} diff --git a/OpenSim/Framework/Communications/Osp/OspResolver.cs b/OpenSim/Framework/Serialization/External/OspResolver.cs similarity index 97% rename from OpenSim/Framework/Communications/Osp/OspResolver.cs rename to OpenSim/Framework/Serialization/External/OspResolver.cs index 24ea64d87f..7e3dd1b79b 100644 --- a/OpenSim/Framework/Communications/Osp/OspResolver.cs +++ b/OpenSim/Framework/Serialization/External/OspResolver.cs @@ -32,7 +32,7 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Services.Interfaces; -namespace OpenSim.Framework.Communications.Osp +namespace OpenSim.Framework.Serialization { /// /// Resolves OpenSim Profile Anchors (OSPA). An OSPA is a string used to provide information for @@ -57,6 +57,12 @@ namespace OpenSim.Framework.Communications.Osp /// The OSPA. Null if a user with the given UUID could not be found. public static string MakeOspa(UUID userId, IUserAccountService userService) { + if (userService == null) + { + m_log.Warn("[OSP RESOLVER]: UserService is null"); + return userId.ToString(); + } + UserAccount account = userService.GetUserAccount(UUID.Zero, userId); if (account != null) return MakeOspa(account.FirstName, account.LastName); diff --git a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs index 862cc72f84..d5e84c779e 100644 --- a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs +++ b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs @@ -26,11 +26,16 @@ */ using System; +using System.Collections.Generic; using System.IO; +using System.Reflection; using System.Text; using System.Xml; + +using log4net; using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Services.Interfaces; namespace OpenSim.Framework.Serialization.External { @@ -40,6 +45,141 @@ namespace OpenSim.Framework.Serialization.External /// XXX: Please do not use yet. public class UserInventoryItemSerializer { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private delegate void InventoryItemXmlProcessor(InventoryItemBase item, XmlTextReader reader); + private static Dictionary m_InventoryItemXmlProcessors = new Dictionary(); + + #region InventoryItemBase Processor initialization + static UserInventoryItemSerializer() + { + m_InventoryItemXmlProcessors.Add("Name", ProcessName); + m_InventoryItemXmlProcessors.Add("ID", ProcessID); + m_InventoryItemXmlProcessors.Add("InvType", ProcessInvType); + m_InventoryItemXmlProcessors.Add("CreatorUUID", ProcessCreatorUUID); + m_InventoryItemXmlProcessors.Add("CreatorID", ProcessCreatorID); + m_InventoryItemXmlProcessors.Add("CreatorData", ProcessCreatorData); + m_InventoryItemXmlProcessors.Add("CreationDate", ProcessCreationDate); + m_InventoryItemXmlProcessors.Add("Owner", ProcessOwner); + m_InventoryItemXmlProcessors.Add("Description", ProcessDescription); + m_InventoryItemXmlProcessors.Add("AssetType", ProcessAssetType); + m_InventoryItemXmlProcessors.Add("AssetID", ProcessAssetID); + m_InventoryItemXmlProcessors.Add("SaleType", ProcessSaleType); + m_InventoryItemXmlProcessors.Add("SalePrice", ProcessSalePrice); + m_InventoryItemXmlProcessors.Add("BasePermissions", ProcessBasePermissions); + m_InventoryItemXmlProcessors.Add("CurrentPermissions", ProcessCurrentPermissions); + m_InventoryItemXmlProcessors.Add("EveryOnePermissions", ProcessEveryOnePermissions); + m_InventoryItemXmlProcessors.Add("NextPermissions", ProcessNextPermissions); + m_InventoryItemXmlProcessors.Add("Flags", ProcessFlags); + m_InventoryItemXmlProcessors.Add("GroupID", ProcessGroupID); + m_InventoryItemXmlProcessors.Add("GroupOwned", ProcessGroupOwned); + } + #endregion + + #region InventoryItemBase Processors + private static void ProcessName(InventoryItemBase item, XmlTextReader reader) + { + item.Name = reader.ReadElementContentAsString("Name", String.Empty); + } + + private static void ProcessID(InventoryItemBase item, XmlTextReader reader) + { + item.ID = Util.ReadUUID(reader, "ID"); + } + + private static void ProcessInvType(InventoryItemBase item, XmlTextReader reader) + { + item.InvType = reader.ReadElementContentAsInt("InvType", String.Empty); + } + + private static void ProcessCreatorUUID(InventoryItemBase item, XmlTextReader reader) + { + item.CreatorId = reader.ReadElementContentAsString("CreatorUUID", String.Empty); + } + + private static void ProcessCreatorID(InventoryItemBase item, XmlTextReader reader) + { + // when it exists, this overrides the previous + item.CreatorId = reader.ReadElementContentAsString("CreatorID", String.Empty); + } + + private static void ProcessCreationDate(InventoryItemBase item, XmlTextReader reader) + { + item.CreationDate = reader.ReadElementContentAsInt("CreationDate", String.Empty); + } + + private static void ProcessOwner(InventoryItemBase item, XmlTextReader reader) + { + item.Owner = Util.ReadUUID(reader, "Owner"); + } + + private static void ProcessDescription(InventoryItemBase item, XmlTextReader reader) + { + item.Description = reader.ReadElementContentAsString("Description", String.Empty); + } + + private static void ProcessAssetType(InventoryItemBase item, XmlTextReader reader) + { + item.AssetType = reader.ReadElementContentAsInt("AssetType", String.Empty); + } + + private static void ProcessAssetID(InventoryItemBase item, XmlTextReader reader) + { + item.AssetID = Util.ReadUUID(reader, "AssetID"); + } + + private static void ProcessSaleType(InventoryItemBase item, XmlTextReader reader) + { + item.SaleType = (byte)reader.ReadElementContentAsInt("SaleType", String.Empty); + } + + private static void ProcessSalePrice(InventoryItemBase item, XmlTextReader reader) + { + item.SalePrice = reader.ReadElementContentAsInt("SalePrice", String.Empty); + } + + private static void ProcessBasePermissions(InventoryItemBase item, XmlTextReader reader) + { + item.BasePermissions = (uint)reader.ReadElementContentAsInt("BasePermissions", String.Empty); + } + + private static void ProcessCurrentPermissions(InventoryItemBase item, XmlTextReader reader) + { + item.CurrentPermissions = (uint)reader.ReadElementContentAsInt("CurrentPermissions", String.Empty); + } + + private static void ProcessEveryOnePermissions(InventoryItemBase item, XmlTextReader reader) + { + item.EveryOnePermissions = (uint)reader.ReadElementContentAsInt("EveryOnePermissions", String.Empty); + } + + private static void ProcessNextPermissions(InventoryItemBase item, XmlTextReader reader) + { + item.NextPermissions = (uint)reader.ReadElementContentAsInt("NextPermissions", String.Empty); + } + + private static void ProcessFlags(InventoryItemBase item, XmlTextReader reader) + { + item.Flags = (uint)reader.ReadElementContentAsInt("Flags", String.Empty); + } + + private static void ProcessGroupID(InventoryItemBase item, XmlTextReader reader) + { + item.GroupID = Util.ReadUUID(reader, "GroupID"); + } + + private static void ProcessGroupOwned(InventoryItemBase item, XmlTextReader reader) + { + item.GroupOwned = Util.ReadBoolean(reader); + } + + private static void ProcessCreatorData(InventoryItemBase item, XmlTextReader reader) + { + item.CreatorData = reader.ReadElementContentAsString("CreatorData", String.Empty); + } + + #endregion + /// /// Deserialize item /// @@ -60,40 +200,47 @@ namespace OpenSim.Framework.Serialization.External public static InventoryItemBase Deserialize(string serialization) { InventoryItemBase item = new InventoryItemBase(); - - StringReader sr = new StringReader(serialization); - XmlTextReader xtr = new XmlTextReader(sr); - - xtr.ReadStartElement("InventoryItem"); - - item.Name = xtr.ReadElementString("Name"); - item.ID = UUID.Parse( xtr.ReadElementString("ID")); - item.InvType = Convert.ToInt32( xtr.ReadElementString("InvType")); - item.CreatorId = xtr.ReadElementString("CreatorUUID"); - item.CreationDate = Convert.ToInt32( xtr.ReadElementString("CreationDate")); - item.Owner = UUID.Parse( xtr.ReadElementString("Owner")); - item.Description = xtr.ReadElementString("Description"); - item.AssetType = Convert.ToInt32( xtr.ReadElementString("AssetType")); - item.AssetID = UUID.Parse( xtr.ReadElementString("AssetID")); - item.SaleType = Convert.ToByte( xtr.ReadElementString("SaleType")); - item.SalePrice = Convert.ToInt32( xtr.ReadElementString("SalePrice")); - item.BasePermissions = Convert.ToUInt32( xtr.ReadElementString("BasePermissions")); - item.CurrentPermissions = Convert.ToUInt32( xtr.ReadElementString("CurrentPermissions")); - item.EveryOnePermissions = Convert.ToUInt32( xtr.ReadElementString("EveryOnePermissions")); - item.NextPermissions = Convert.ToUInt32( xtr.ReadElementString("NextPermissions")); - item.Flags = Convert.ToUInt32( xtr.ReadElementString("Flags")); - item.GroupID = UUID.Parse( xtr.ReadElementString("GroupID")); - item.GroupOwned = Convert.ToBoolean(xtr.ReadElementString("GroupOwned")); - - xtr.ReadEndElement(); - - xtr.Close(); - sr.Close(); - + + using (XmlTextReader reader = new XmlTextReader(new StringReader(serialization))) + { + reader.ReadStartElement("InventoryItem"); + + string nodeName = string.Empty; + while (reader.NodeType != XmlNodeType.EndElement) + { + nodeName = reader.Name; + InventoryItemXmlProcessor p = null; + if (m_InventoryItemXmlProcessors.TryGetValue(reader.Name, out p)) + { + //m_log.DebugFormat("[XXX] Processing: {0}", reader.Name); + try + { + p(item, reader); + } + catch (Exception e) + { + m_log.DebugFormat("[InventoryItemSerializer]: exception while parsing {0}: {1}", nodeName, e); + if (reader.NodeType == XmlNodeType.EndElement) + reader.Read(); + } + } + else + { + // m_log.DebugFormat("[InventoryItemSerializer]: caught unknown element {0}", nodeName); + reader.ReadOuterXml(); // ignore + } + + } + + reader.ReadEndElement(); // InventoryItem + } + + //m_log.DebugFormat("[XXX]: parsed InventoryItemBase {0} - {1}", obj.Name, obj.UUID); return item; + } - public static string Serialize(InventoryItemBase inventoryItem) + public static string Serialize(InventoryItemBase inventoryItem, Dictionary options, IUserAccountService userAccountService) { StringWriter sw = new StringWriter(); XmlTextWriter writer = new XmlTextWriter(sw); @@ -112,7 +259,7 @@ namespace OpenSim.Framework.Serialization.External writer.WriteString(inventoryItem.InvType.ToString()); writer.WriteEndElement(); writer.WriteStartElement("CreatorUUID"); - writer.WriteString(inventoryItem.CreatorId); + writer.WriteString(OspResolver.MakeOspa(inventoryItem.CreatorIdAsUuid, userAccountService)); writer.WriteEndElement(); writer.WriteStartElement("CreationDate"); writer.WriteString(inventoryItem.CreationDate.ToString()); @@ -156,6 +303,20 @@ namespace OpenSim.Framework.Serialization.External writer.WriteStartElement("GroupOwned"); writer.WriteString(inventoryItem.GroupOwned.ToString()); writer.WriteEndElement(); + if (inventoryItem.CreatorData != null && inventoryItem.CreatorData != string.Empty) + writer.WriteElementString("CreatorData", inventoryItem.CreatorData); + else if (options.ContainsKey("profile")) + { + if (userAccountService != null) + { + UserAccount account = userAccountService.GetUserAccount(UUID.Zero, inventoryItem.CreatorIdAsUuid); + if (account != null) + { + writer.WriteElementString("CreatorData", (string)options["profile"] + "/" + inventoryItem.CreatorIdAsUuid + ";" + account.FirstName + " " + account.LastName); + } + writer.WriteElementString("CreatorID", inventoryItem.CreatorId); + } + } writer.WriteEndElement(); diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 6bee4bed3c..877b0c2d38 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1558,5 +1558,86 @@ namespace OpenSim.Framework return string.Empty; } + #region Xml Serialization Utilities + public static bool ReadBoolean(XmlTextReader reader) + { + reader.ReadStartElement(); + bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); + reader.ReadEndElement(); + + return result; + } + + public static UUID ReadUUID(XmlTextReader reader, string name) + { + UUID id; + string idStr; + + reader.ReadStartElement(name); + + if (reader.Name == "Guid") + idStr = reader.ReadElementString("Guid"); + else if (reader.Name == "UUID") + idStr = reader.ReadElementString("UUID"); + else // no leading tag + idStr = reader.ReadContentAsString(); + UUID.TryParse(idStr, out id); + reader.ReadEndElement(); + + return id; + } + + public static Vector3 ReadVector(XmlTextReader reader, string name) + { + Vector3 vec; + + reader.ReadStartElement(name); + vec.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // X or x + vec.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Y or y + vec.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Z or z + reader.ReadEndElement(); + + return vec; + } + + public static Quaternion ReadQuaternion(XmlTextReader reader, string name) + { + Quaternion quat = new Quaternion(); + + reader.ReadStartElement(name); + while (reader.NodeType != XmlNodeType.EndElement) + { + switch (reader.Name.ToLower()) + { + case "x": + quat.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "y": + quat.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "z": + quat.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "w": + quat.W = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + } + } + + reader.ReadEndElement(); + + return quat; + } + + public static T ReadEnum(XmlTextReader reader, string name) + { + string value = reader.ReadElementContentAsString(name, String.Empty); + // !!!!! to deal with flags without commas + if (value.Contains(" ") && !value.Contains(",")) + value = value.Replace(" ", ", "); + + return (T)Enum.Parse(typeof(T), value); ; + } + #endregion } } diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 493d4127ee..feaea16c6b 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -265,10 +265,10 @@ namespace OpenSim LoadOar); m_console.Commands.AddCommand("region", false, "save oar", - "save oar [-v|--version=N] [-p|--profile=url] []", + "save oar [-v|--version=] [-p|--profile=] []", "Save a region's data to an OAR archive.", - "-v|--version=N generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine - + "-p|--profile=url adds the url of the profile service to the saved user information" + Environment.NewLine + "-v|--version= generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine + + "-p|--profile= adds the url of the profile service to the saved user information" + Environment.NewLine + "The OAR path must be a filesystem path." + " If this is not given then the oar is saved to region.oar in the current directory.", SaveOar); diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index f99fa167f2..9189260c59 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -3598,14 +3598,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP EntityUpdate update; while (updatesThisCall < maxUpdates && m_entityUpdates.TryDequeue(out update)) { - // If we have sent a kill packet for this object - // drop any updates on the floor if (update.Entity is SceneObjectPart) { SceneObjectPart part = (SceneObjectPart)update.Entity; if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId)) continue; + // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client + // will never receive an update after a prim kill. Even then, keeping the kill record may be a good + // safety measure. + // + // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update + // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs + // updates and kills on different threads with different scheduling strategies, hence this protection. + // + // This doesn't appear to apply to child prims - a client will happily ignore these updates + // after the root prim has been deleted. + if (m_killRecord.Contains(part.LocalId)) + { + // m_log.WarnFormat( + // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", + // part.LocalId, Name); + continue; + } + if (part.ParentGroup.IsAttachment && m_disableFacelights) { if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index ed0e60d9eb..5aa9b40de4 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -400,7 +400,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP return data; } - public bool EnqueueOutgoing(OutgoingPacket packet) + /// + /// Queue an outgoing packet if appropriate. + /// + /// + /// Always queue the packet if at all possible. + /// + /// true if the packet has been queued, + /// false if the packet has not been queued and should be sent immediately. + /// + public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) { int category = (int)packet.Category; @@ -416,14 +425,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP TokenBucket bucket = m_throttleCategories[category]; - if (bucket.RemoveTokens(packet.Buffer.DataLength)) + if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) { // Enough tokens were removed from the bucket, the packet will not be queued return false; } else { - // Not enough tokens in the bucket, queue this packet + // Force queue specified or not enough tokens in the bucket, queue this packet queue.Enqueue(packet); return true; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index ef0a178448..69854497c2 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -312,6 +312,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + /// + /// Start the process of sending a packet to the client. + /// + /// + /// + /// + /// public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting) { // CoarseLocationUpdate packets cannot be split in an automated way @@ -339,6 +346,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + /// + /// Start the process of sending a packet to the client. + /// + /// + /// + /// + /// public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category) { int dataLength = data.Length; @@ -396,7 +410,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); - if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) + // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will + // continue to display the deleted object until relog. Therefore, we need to always queue a kill object + // packet so that it isn't sent before a queued update packet. + bool requestQueue = type == PacketType.KillObject; + if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) SendPacketFinal(outgoingPacket); #endregion Queue or Send @@ -489,7 +507,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP //Interlocked.Increment(ref Stats.ResentPackets); // Requeue or resend the packet - if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) + if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false)) SendPacketFinal(outgoingPacket); } } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index 046b05f48e..acf2c3ef97 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs @@ -37,12 +37,11 @@ using System.Xml.Linq; using log4net; using OpenMetaverse; using OpenSim.Framework; -using OpenSim.Framework.Communications; -using OpenSim.Framework.Communications.Osp; using OpenSim.Framework.Serialization; using OpenSim.Framework.Serialization.External; using OpenSim.Region.CoreModules.World.Archiver; using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver @@ -398,20 +397,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // Don't use the item ID that's in the file item.ID = UUID.Random(); - UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_scene.UserAccountService); - if (UUID.Zero != ospResolvedId) + UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_scene.UserAccountService); + if (UUID.Zero != ospResolvedId) // The user exists in this grid { item.CreatorIdAsUuid = ospResolvedId; // XXX: For now, don't preserve the OSPA in the creator id (which actually gets persisted to the // database). Instead, replace with the UUID that we found. item.CreatorId = ospResolvedId.ToString(); + + item.CreatorData = string.Empty; } - else + else if (item.CreatorData == null || item.CreatorData == String.Empty) { item.CreatorIdAsUuid = m_userInfo.PrincipalID; } - + item.Owner = m_userInfo.PrincipalID; // Reset folder ID to the one in which we want to load it diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs index d81703a827..cab341dbff 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs @@ -36,8 +36,6 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Serialization; using OpenSim.Framework.Serialization.External; -using OpenSim.Framework.Communications; -using OpenSim.Framework.Communications.Osp; using OpenSim.Region.CoreModules.World.Archiver; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; @@ -139,20 +137,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_id, succeeded, m_userInfo, m_invPath, m_saveStream, reportedException); } - protected void SaveInvItem(InventoryItemBase inventoryItem, string path) + protected void SaveInvItem(InventoryItemBase inventoryItem, string path, Dictionary options, IUserAccountService userAccountService) { string filename = path + CreateArchiveItemName(inventoryItem); // Record the creator of this item for user record purposes (which might go away soon) m_userUuids[inventoryItem.CreatorIdAsUuid] = 1; - InventoryItemBase saveItem = (InventoryItemBase)inventoryItem.Clone(); - saveItem.CreatorId = OspResolver.MakeOspa(saveItem.CreatorIdAsUuid, m_scene.UserAccountService); - - string serialization = UserInventoryItemSerializer.Serialize(saveItem); + string serialization = UserInventoryItemSerializer.Serialize(inventoryItem, options, userAccountService); m_archiveWriter.WriteFile(filename, serialization); - m_assetGatherer.GatherAssetUuids(saveItem.AssetID, (AssetType)saveItem.AssetType, m_assetUuids); + m_assetGatherer.GatherAssetUuids(inventoryItem.AssetID, (AssetType)inventoryItem.AssetType, m_assetUuids); } /// @@ -161,7 +156,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// The inventory folder to save /// The path to which the folder should be saved /// If true, save this folder itself. If false, only saves contents - protected void SaveInvFolder(InventoryFolderBase inventoryFolder, string path, bool saveThisFolderItself) + protected void SaveInvFolder(InventoryFolderBase inventoryFolder, string path, bool saveThisFolderItself, Dictionary options, IUserAccountService userAccountService) { if (saveThisFolderItself) { @@ -176,19 +171,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver foreach (InventoryFolderBase childFolder in contents.Folders) { - SaveInvFolder(childFolder, path, true); + SaveInvFolder(childFolder, path, true, options, userAccountService); } foreach (InventoryItemBase item in contents.Items) { - SaveInvItem(item, path); + SaveInvItem(item, path, options, userAccountService); } } /// /// Execute the inventory write request /// - public void Execute() + public void Execute(Dictionary options, IUserAccountService userAccountService) { try { @@ -266,7 +261,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_invPath == String.Empty ? InventoryFolderImpl.PATH_DELIMITER : m_invPath); //recurse through all dirs getting dirs and files - SaveInvFolder(inventoryFolder, ArchiveConstants.INVENTORY_PATH, !saveFolderContentsOnly); + SaveInvFolder(inventoryFolder, ArchiveConstants.INVENTORY_PATH, !saveFolderContentsOnly, options, userAccountService); } else if (inventoryItem != null) { @@ -274,14 +269,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver "[INVENTORY ARCHIVER]: Found item {0} {1} at {2}", inventoryItem.Name, inventoryItem.ID, m_invPath); - SaveInvItem(inventoryItem, ArchiveConstants.INVENTORY_PATH); + SaveInvItem(inventoryItem, ArchiveConstants.INVENTORY_PATH, options, userAccountService); } // Don't put all this profile information into the archive right now. //SaveUsers(); new AssetsRequest( - new AssetsArchiver(m_archiveWriter), m_assetUuids, m_scene.AssetService, ReceivedAllAssets).Execute(); + new AssetsArchiver(m_archiveWriter), + m_assetUuids, m_scene.AssetService, + m_scene.UserAccountService, m_scene.RegionInfo.ScopeID, + options, ReceivedAllAssets).Execute(); } catch (Exception) { diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs index 2eaca499b0..b33c2b1af5 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs @@ -75,6 +75,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver private Dictionary m_scenes = new Dictionary(); private Scene m_aScene; + private IUserAccountService m_UserAccountService; + protected IUserAccountService UserAccountService + { + get + { + if (m_UserAccountService == null) + // What a strange thing to do... + foreach (Scene s in m_scenes.Values) + { + m_UserAccountService = s.RequestModuleInterface(); + break; + } + + return m_UserAccountService; + } + } + + public InventoryArchiverModule() {} public InventoryArchiverModule(bool disablePresenceChecks) @@ -106,11 +124,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver scene.AddCommand( this, "save iar", - "save iar []", + "save iar [--p|-profile=] []", "Save user inventory archive (IAR).", " is the user's first name." + Environment.NewLine + " is the user's last name." + Environment.NewLine + " is the path inside the user's inventory for the folder/item to be saved." + Environment.NewLine + + "-p|--profile= adds the url of the profile service to the saved user information." + Environment.NewLine + " is the filesystem path at which to save the IAR." + string.Format(" If this is not given then the filename {0} in the current directory is used", DEFAULT_INV_BACKUP_FILENAME), HandleSaveInvConsoleCommand); @@ -157,7 +176,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { try { - new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, saveStream).Execute(); + new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, saveStream).Execute(options, UserAccountService); } catch (EntryPointNotFoundException e) { @@ -197,7 +216,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { try { - new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, savePath).Execute(); + new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, savePath).Execute(options, UserAccountService); } catch (EntryPointNotFoundException e) { @@ -235,14 +254,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (m_scenes.Count > 0) { UserAccount userInfo = GetUserInfo(firstName, lastName, pass); - + if (userInfo != null) { if (CheckPresence(userInfo.PrincipalID)) { + InventoryArchiveReadRequest request; bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false); - + try { request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream, merge); @@ -256,7 +276,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return false; } - + UpdateClientWithLoadedNodes(userInfo, request.Execute()); return true; @@ -268,6 +288,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID); } } + else + m_log.ErrorFormat("[INVENTORY ARCHIVER]: User {0} {1} not found", + firstName, lastName); } return false; @@ -368,10 +391,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver protected void HandleSaveInvConsoleCommand(string module, string[] cmdparams) { Guid id = Guid.NewGuid(); - + + Dictionary options = new Dictionary(); + + OptionSet ops = new OptionSet(); + //ops.Add("v|version=", delegate(string v) { options["version"] = v; }); + ops.Add("p|profile=", delegate(string v) { options["profile"] = v; }); + + List mainParams = ops.Parse(cmdparams); + try { - if (cmdparams.Length < 6) + if (mainParams.Count < 6) { m_log.Error( "[INVENTORY ARCHIVER]: usage is save iar []"); @@ -379,18 +410,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver } m_log.Info("[INVENTORY ARCHIVER]: PLEASE NOTE THAT THIS FACILITY IS EXPERIMENTAL. BUG REPORTS WELCOME."); - - string firstName = cmdparams[2]; - string lastName = cmdparams[3]; - string invPath = cmdparams[4]; - string pass = cmdparams[5]; - string savePath = (cmdparams.Length > 6 ? cmdparams[6] : DEFAULT_INV_BACKUP_FILENAME); + if (options.ContainsKey("profile")) + m_log.WarnFormat("[INVENTORY ARCHIVER]: Please be aware that inventory archives with creator information are not compatible with OpenSim 0.7.0.2 and earlier. Do not use the -profile option if you want to produce a compatible IAR"); + + string firstName = mainParams[2]; + string lastName = mainParams[3]; + string invPath = mainParams[4]; + string pass = mainParams[5]; + string savePath = (mainParams.Count > 6 ? mainParams[6] : DEFAULT_INV_BACKUP_FILENAME); m_log.InfoFormat( "[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}", savePath, invPath, firstName, lastName); - ArchiveInventory(id, firstName, lastName, invPath, pass, savePath, new Dictionary()); + ArchiveInventory(id, firstName, lastName, invPath, pass, savePath, options); } catch (InventoryArchiverException e) { @@ -518,5 +551,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return false; } + } } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index 938886b2d3..2747e157be 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -38,7 +38,6 @@ using OpenSim.Framework; using OpenSim.Framework.Serialization; using OpenSim.Framework.Serialization.External; using OpenSim.Framework.Communications; -using OpenSim.Framework.Communications.Osp; using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; using OpenSim.Region.CoreModules.World.Serialiser; using OpenSim.Region.Framework.Scenes; @@ -96,14 +95,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests item1.Name = m_item1Name; item1.AssetID = UUID.Random(); item1.GroupID = UUID.Random(); - item1.CreatorId = OspResolver.MakeOspa(m_ua2.FirstName, m_ua2.LastName); + //item1.CreatorId = OspResolver.MakeOspa(m_ua2.FirstName, m_ua2.LastName); //item1.CreatorId = userUuid.ToString(); - //item1.CreatorId = "00000000-0000-0000-0000-000000000444"; + item1.CreatorId = m_ua2.PrincipalID.ToString(); item1.Owner = UUID.Zero; - + + Scene scene = SceneSetupHelpers.SetupScene("Inventory"); + UserProfileTestUtils.CreateUserWithInventory(scene, m_ua2, "hampshire"); + string item1FileName = string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, archiveItemName); - tar.WriteFile(item1FileName, UserInventoryItemSerializer.Serialize(item1)); + tar.WriteFile(item1FileName, UserInventoryItemSerializer.Serialize(item1, new Dictionary(), scene.UserAccountService)); tar.Close(); m_iarStream = new MemoryStream(archiveWriteStream.ToArray()); } @@ -386,7 +388,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests Scene scene = SceneSetupHelpers.SetupScene("inventory"); SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); - + UserProfileTestUtils.CreateUserWithInventory(scene, m_ua1, "meowfood"); UserProfileTestUtils.CreateUserWithInventory(scene, m_ua2, "hampshire"); @@ -551,7 +553,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests string item1FileName = string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, archiveItemName); - tar.WriteFile(item1FileName, UserInventoryItemSerializer.Serialize(item1)); + tar.WriteFile(item1FileName, UserInventoryItemSerializer.Serialize(item1, new Dictionary(), null)); tar.Close(); MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs index ccb892e1e4..81b65c5727 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs @@ -27,8 +27,11 @@ using System; using System.Collections.Generic; +using System.IO; using System.Reflection; using System.Threading; +using System.Xml; + using log4net; using OpenMetaverse; using OpenSim.Framework; @@ -52,14 +55,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // private Dictionary m_inventoryServers = new Dictionary(); private Scene m_scene; + private string m_ProfileServerURI; #endregion #region Constructor - public HGAssetMapper(Scene scene) + public HGAssetMapper(Scene scene, string profileURL) { m_scene = scene; + m_ProfileServerURI = profileURL; } #endregion @@ -95,16 +100,18 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess try { asset1.ID = url + "/" + asset.ID; -// UUID temp = UUID.Zero; - // TODO: if the creator is local, stick this grid's URL in front - //if (UUID.TryParse(asset.Metadata.CreatorID, out temp)) - // asset1.Metadata.CreatorID = ??? + "/" + asset.Metadata.CreatorID; } catch { m_log.Warn("[HG ASSET MAPPER]: Oops."); } + AdjustIdentifiers(asset1.Metadata); + if (asset1.Metadata.Type == (sbyte)AssetType.Object) + asset1.Data = AdjustIdentifiers(asset.Data); + else + asset1.Data = asset.Data; + m_scene.AssetService.Store(asset1); m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url); } @@ -118,7 +125,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess private void Copy(AssetBase from, AssetBase to) { - to.Data = from.Data; + //to.Data = from.Data; // don't copy this, it's copied elsewhere to.Description = from.Description; to.FullID = from.FullID; to.ID = from.ID; @@ -129,6 +136,70 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } + private void AdjustIdentifiers(AssetMetadata meta) + { + if (meta.CreatorID != null && meta.CreatorID != string.Empty) + { + UUID uuid = UUID.Zero; + UUID.TryParse(meta.CreatorID, out uuid); + UserAccount creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); + if (creator != null) + meta.CreatorID = m_ProfileServerURI + "/" + meta.CreatorID + ";" + creator.FirstName + " " + creator.LastName; + } + } + + protected byte[] AdjustIdentifiers(byte[] data) + { + string xml = Utils.BytesToString(data); + return Utils.StringToBytes(RewriteSOP(xml)); + } + + protected string RewriteSOP(string xml) + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + XmlNodeList sops = doc.GetElementsByTagName("SceneObjectPart"); + + foreach (XmlNode sop in sops) + { + UserAccount creator = null; + bool hasCreatorData = false; + XmlNodeList nodes = sop.ChildNodes; + foreach (XmlNode node in nodes) + { + if (node.Name == "CreatorID") + { + UUID uuid = UUID.Zero; + UUID.TryParse(node.InnerText, out uuid); + creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); + } + if (node.Name == "CreatorData" && node.InnerText != null && node.InnerText != string.Empty) + hasCreatorData = true; + + //if (node.Name == "OwnerID") + //{ + // UserAccount owner = GetUser(node.InnerText); + // if (owner != null) + // node.InnerText = m_ProfileServiceURL + "/" + node.InnerText + "/" + owner.FirstName + " " + owner.LastName; + //} + } + + if (!hasCreatorData && creator != null) + { + XmlElement creatorData = doc.CreateElement("CreatorData"); + creatorData.InnerText = m_ProfileServerURI + "/" + creator.PrincipalID + ";" + creator.FirstName + " " + creator.LastName; + sop.AppendChild(creatorData); + } + } + + using (StringWriter wr = new StringWriter()) + { + doc.Save(wr); + return wr.ToString(); + } + + } + // TODO: unused // private void Dump(Dictionary lst) // { diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 125a397d0e..34b811428d 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -54,6 +54,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess get { return m_assMapper; } } + private string m_ProfileServerURI; + // private bool m_Initialized = false; #region INonSharedRegionModule @@ -73,6 +75,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { m_Enabled = true; m_log.InfoFormat("[HG INVENTORY ACCESS MODULE]: {0} enabled.", Name); + + IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"]; + if (thisModuleConfig != null) + m_ProfileServerURI = thisModuleConfig.GetString("ProfileServerURI", string.Empty); + else + m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!"); } } } @@ -83,7 +91,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return; base.AddRegion(scene); - m_assMapper = new HGAssetMapper(scene); + m_assMapper = new HGAssetMapper(scene, m_ProfileServerURI); scene.EventManager.OnNewInventoryItemUploadComplete += UploadInventoryItem; } @@ -97,7 +105,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess string userAssetServer = string.Empty; if (IsForeignUser(avatarID, out userAssetServer)) { - m_assMapper.Post(assetID, avatarID, userAssetServer); + Util.FireAndForget(delegate { m_assMapper.Post(assetID, avatarID, userAssetServer); }); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 22da665ac2..623cd3a900 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -54,6 +54,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess protected bool m_Enabled = false; protected Scene m_Scene; + protected IUserManagement m_UserManagement; + protected IUserManagement UserManagementModule + { + get + { + if (m_UserManagement == null) + m_UserManagement = m_Scene.RequestModuleInterface(); + return m_UserManagement; + } + } + #region INonSharedRegionModule @@ -416,7 +427,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) { - if (objlist[0].RootPart.FromFolderID != UUID.Zero) + if (objlist[0].RootPart.FromFolderID != UUID.Zero && objlist[0].OwnerID == remoteClient.AgentId) { InventoryFolderBase f = new InventoryFolderBase(objlist[0].RootPart.FromFolderID, userID); folder = m_Scene.InventoryService.GetFolder(f); @@ -863,6 +874,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return null; } + protected void AddUserData(SceneObjectGroup sog) + { + UserManagementModule.AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData); + foreach (SceneObjectPart sop in sog.Parts) + UserManagementModule.AddUser(sop.CreatorID, sop.CreatorData); + } + public virtual void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver) { } @@ -943,9 +961,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess protected virtual InventoryItemBase GetItem(UUID agentID, UUID itemID) { IInventoryService invService = m_Scene.RequestModuleInterface(); - InventoryItemBase assetRequestItem = new InventoryItemBase(itemID, agentID); - assetRequestItem = invService.GetItem(assetRequestItem); - return assetRequestItem; + InventoryItemBase item = new InventoryItemBase(itemID, agentID); + item = invService.GetItem(item); + + if (item.CreatorData != null && item.CreatorData != string.Empty) + UserManagementModule.AddUser(item.CreatorIdAsUuid, item.CreatorData); + + return item; } #endregion diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 0d94baa2fa..bf84100ef5 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -275,6 +275,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement m_log.DebugFormat("[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}", user.Id, user.FirstName, user.LastName, user.ProfileURL); } + public void AddUser(UUID uuid, string first, string last, string profileURL) + { + AddUser(uuid, profileURL + ";" + first + " " + last); + } + //public void AddUser(UUID uuid, string userData) //{ // if (m_UserCache.ContainsKey(uuid)) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs index 232438031c..e25700d1f7 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs @@ -91,9 +91,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Asset { m_Registered = true; - m_log.Info("[RegionAssetService]: Starting..."); + m_log.Info("[HGAssetService]: Starting..."); - Object[] args = new Object[] { m_Config, MainServer.Instance, string.Empty }; + + Object[] args = new Object[] { m_Config, MainServer.Instance, "HGAssetService" }; ServerUtils.LoadPlugin("OpenSim.Server.Handlers.dll:AssetServiceConnector", args); } diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs index b987b5ac82..0699407d12 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs @@ -190,7 +190,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver new AssetsRequest( new AssetsArchiver(archiveWriter), assetUuids, - m_scene.AssetService, awre.ReceivedAllAssets).Execute(); + m_scene.AssetService, m_scene.UserAccountService, + m_scene.RegionInfo.ScopeID, options, awre.ReceivedAllAssets).Execute(); } catch (Exception) { @@ -238,10 +239,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver } m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion); - if (majorVersion == 1) - { - m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim 0.7.0.2 and earlier. Please use the --version=0 option if you want to produce a compatible OAR"); - } + //if (majorVersion == 1) + //{ + // m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim 0.7.0.2 and earlier. Please use the --version=0 option if you want to produce a compatible OAR"); + //} StringWriter sw = new StringWriter(); XmlTextWriter xtw = new XmlTextWriter(sw); diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs index d4a09b45f7..5da165666d 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs @@ -34,6 +34,7 @@ using log4net; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Serialization; +using OpenSim.Framework.Serialization.External; using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.World.Archiver @@ -100,17 +101,26 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// Asset service used to request the assets /// protected IAssetService m_assetService; + protected IUserAccountService m_userAccountService; + protected UUID m_scopeID; // the grid ID protected AssetsArchiver m_assetsArchiver; + protected Dictionary m_options; + protected internal AssetsRequest( AssetsArchiver assetsArchiver, IDictionary uuids, - IAssetService assetService, AssetsRequestCallback assetsRequestCallback) + IAssetService assetService, IUserAccountService userService, + UUID scope, Dictionary options, + AssetsRequestCallback assetsRequestCallback) { m_assetsArchiver = assetsArchiver; m_uuids = uuids; m_assetsRequestCallback = assetsRequestCallback; m_assetService = assetService; + m_userAccountService = userService; + m_scopeID = scope; + m_options = options; m_repliesRequired = uuids.Count; m_requestCallbackTimer = new System.Timers.Timer(TIMEOUT); @@ -241,7 +251,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver { // m_log.DebugFormat("[ARCHIVER]: Writing asset {0}", id); m_foundAssetUuids.Add(asset.FullID); - m_assetsArchiver.WriteAsset(asset); + + m_assetsArchiver.WriteAsset(PostProcess(asset)); } else { @@ -288,5 +299,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver "[ARCHIVER]: Terminating archive creation since asset requster callback failed with {0}", e); } } + + protected AssetBase PostProcess(AssetBase asset) + { + if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("profile")) + { + //m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID); + string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), m_options["profile"].ToString(), m_userAccountService, m_scopeID); + asset.Data = Utils.StringToBytes(xml); + } + return asset; + } } } diff --git a/OpenSim/Region/Framework/Interfaces/IUserManagement.cs b/OpenSim/Region/Framework/Interfaces/IUserManagement.cs index 1a5cb7ecd1..2904ee87dc 100644 --- a/OpenSim/Region/Framework/Interfaces/IUserManagement.cs +++ b/OpenSim/Region/Framework/Interfaces/IUserManagement.cs @@ -9,5 +9,6 @@ namespace OpenSim.Region.Framework.Interfaces { string GetUserName(UUID uuid); void AddUser(UUID uuid, string userData); + void AddUser(UUID uuid, string firstName, string lastName, string profileURL); } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index e6201a81e0..52e2e83cf4 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -398,6 +398,10 @@ namespace OpenSim.Region.Framework.Scenes if ((item != null) && (item.Owner == senderId)) { + IUserManagement uman = RequestModuleInterface(); + if (uman != null) + uman.AddUser(item.CreatorIdAsUuid, item.CreatorData); + if (!Permissions.BypassPermissions()) { if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 3c2cd9bdba..0c7b2e8dc8 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2059,7 +2059,7 @@ namespace OpenSim.Region.Framework.Scenes /// Object Id /// Suppress broadcasting changes to other clients. public void DeleteSceneObject(SceneObjectGroup group, bool silent) - { + { // m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID); //SceneObjectPart rootPart = group.GetChildPart(group.UUID); @@ -2102,7 +2102,7 @@ namespace OpenSim.Region.Framework.Scenes if (!silent) SendKillObject(new List() { group.LocalId }); -// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); +// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); } /// @@ -2121,9 +2121,12 @@ namespace OpenSim.Region.Framework.Scenes // Force a database update so that the scene object group ID is accurate. It's possible that the // group has recently been delinked from another group but that this change has not been persisted // to the DB. - ForceSceneObjectBackup(so); + // This is an expensive thing to do so only do it if absolutely necessary. + if (so.HasGroupChangedDueToDelink) + ForceSceneObjectBackup(so); + so.DetachFromBackup(); - SimulationDataService.RemoveObject(so.UUID, m_regInfo.RegionID); + SimulationDataService.RemoveObject(so.UUID, m_regInfo.RegionID); } // We need to keep track of this state in case this group is still queued for further backup. @@ -2650,6 +2653,7 @@ namespace OpenSim.Region.Framework.Scenes } else m_log.DebugFormat("[SCENE]: User Client Verification for {0} {1} in {2} returned true", aCircuit.firstname, aCircuit.lastname, RegionInfo.RegionName); + } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index bcb715ba28..896300f0e0 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -171,10 +171,19 @@ namespace OpenSim.Region.Framework.Scenes } } m_hasGroupChanged = value; + +// m_log.DebugFormat( +// "[SCENE OBJECT GROUP]: HasGroupChanged set to {0} for {1} {2}", m_hasGroupChanged, Name, LocalId); } get { return m_hasGroupChanged; } } + + /// + /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since + /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. + /// + public bool HasGroupChangedDueToDelink { get; private set; } private bool isTimeToPersist() { @@ -1622,6 +1631,7 @@ namespace OpenSim.Region.Framework.Scenes backup_group.RootPart.AngularVelocity = RootPart.AngularVelocity; backup_group.RootPart.ParticleSystem = RootPart.ParticleSystem; HasGroupChanged = false; + HasGroupChangedDueToDelink = false; m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); @@ -2540,8 +2550,9 @@ namespace OpenSim.Region.Framework.Scenes linkPart.Rezzed = RootPart.Rezzed; - //HasGroupChanged = true; - //ScheduleGroupForFullUpdate(); + // When we delete a group, we currently have to force persist to the database if the object id has changed + // (since delete works by deleting all rows which have a given object id) + objectGroup.HasGroupChangedDueToDelink = true; return objectGroup; } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 8cc2be1b8a..db60ae302d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -459,7 +459,10 @@ namespace OpenSim.Region.Framework.Scenes } } - public string CreatorData // = ; + /// + /// Data about the creator in the form profile_url;name + /// + public string CreatorData { get { return m_creatorData; } set { m_creatorData = value; } diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 1fe31b0c67..6c13eb5736 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -409,12 +409,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization #region SOPXmlProcessors private static void ProcessAllowedDrop(SceneObjectPart obj, XmlTextReader reader) { - obj.AllowedDrop = reader.ReadElementContentAsBoolean("AllowedDrop", String.Empty); + obj.AllowedDrop = Util.ReadBoolean(reader); } private static void ProcessCreatorID(SceneObjectPart obj, XmlTextReader reader) { - obj.CreatorID = ReadUUID(reader, "CreatorID"); + obj.CreatorID = Util.ReadUUID(reader, "CreatorID"); } private static void ProcessCreatorData(SceneObjectPart obj, XmlTextReader reader) @@ -424,7 +424,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessFolderID(SceneObjectPart obj, XmlTextReader reader) { - obj.FolderID = ReadUUID(reader, "FolderID"); + obj.FolderID = Util.ReadUUID(reader, "FolderID"); } private static void ProcessInventorySerial(SceneObjectPart obj, XmlTextReader reader) @@ -439,7 +439,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessUUID(SceneObjectPart obj, XmlTextReader reader) { - obj.UUID = ReadUUID(reader, "UUID"); + obj.UUID = Util.ReadUUID(reader, "UUID"); } private static void ProcessLocalId(SceneObjectPart obj, XmlTextReader reader) @@ -459,7 +459,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessPassTouches(SceneObjectPart obj, XmlTextReader reader) { - obj.PassTouches = reader.ReadElementContentAsBoolean("PassTouches", String.Empty); + obj.PassTouches = Util.ReadBoolean(reader); } private static void ProcessRegionHandle(SceneObjectPart obj, XmlTextReader reader) @@ -474,32 +474,32 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessGroupPosition(SceneObjectPart obj, XmlTextReader reader) { - obj.GroupPosition = ReadVector(reader, "GroupPosition"); + obj.GroupPosition = Util.ReadVector(reader, "GroupPosition"); } private static void ProcessOffsetPosition(SceneObjectPart obj, XmlTextReader reader) { - obj.OffsetPosition = ReadVector(reader, "OffsetPosition"); ; + obj.OffsetPosition = Util.ReadVector(reader, "OffsetPosition"); ; } private static void ProcessRotationOffset(SceneObjectPart obj, XmlTextReader reader) { - obj.RotationOffset = ReadQuaternion(reader, "RotationOffset"); + obj.RotationOffset = Util.ReadQuaternion(reader, "RotationOffset"); } private static void ProcessVelocity(SceneObjectPart obj, XmlTextReader reader) { - obj.Velocity = ReadVector(reader, "Velocity"); + obj.Velocity = Util.ReadVector(reader, "Velocity"); } private static void ProcessAngularVelocity(SceneObjectPart obj, XmlTextReader reader) { - obj.AngularVelocity = ReadVector(reader, "AngularVelocity"); + obj.AngularVelocity = Util.ReadVector(reader, "AngularVelocity"); } private static void ProcessAcceleration(SceneObjectPart obj, XmlTextReader reader) { - obj.Acceleration = ReadVector(reader, "Acceleration"); + obj.Acceleration = Util.ReadVector(reader, "Acceleration"); } private static void ProcessDescription(SceneObjectPart obj, XmlTextReader reader) @@ -553,7 +553,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessScale(SceneObjectPart obj, XmlTextReader reader) { - obj.Scale = ReadVector(reader, "Scale"); + obj.Scale = Util.ReadVector(reader, "Scale"); } private static void ProcessUpdateFlag(SceneObjectPart obj, XmlTextReader reader) @@ -563,22 +563,22 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessSitTargetOrientation(SceneObjectPart obj, XmlTextReader reader) { - obj.SitTargetOrientation = ReadQuaternion(reader, "SitTargetOrientation"); + obj.SitTargetOrientation = Util.ReadQuaternion(reader, "SitTargetOrientation"); } private static void ProcessSitTargetPosition(SceneObjectPart obj, XmlTextReader reader) { - obj.SitTargetPosition = ReadVector(reader, "SitTargetPosition"); + obj.SitTargetPosition = Util.ReadVector(reader, "SitTargetPosition"); } private static void ProcessSitTargetPositionLL(SceneObjectPart obj, XmlTextReader reader) { - obj.SitTargetPositionLL = ReadVector(reader, "SitTargetPositionLL"); + obj.SitTargetPositionLL = Util.ReadVector(reader, "SitTargetPositionLL"); } private static void ProcessSitTargetOrientationLL(SceneObjectPart obj, XmlTextReader reader) { - obj.SitTargetOrientationLL = ReadQuaternion(reader, "SitTargetOrientationLL"); + obj.SitTargetOrientationLL = Util.ReadQuaternion(reader, "SitTargetOrientationLL"); } private static void ProcessParentID(SceneObjectPart obj, XmlTextReader reader) @@ -614,17 +614,17 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessGroupID(SceneObjectPart obj, XmlTextReader reader) { - obj.GroupID = ReadUUID(reader, "GroupID"); + obj.GroupID = Util.ReadUUID(reader, "GroupID"); } private static void ProcessOwnerID(SceneObjectPart obj, XmlTextReader reader) { - obj.OwnerID = ReadUUID(reader, "OwnerID"); + obj.OwnerID = Util.ReadUUID(reader, "OwnerID"); } private static void ProcessLastOwnerID(SceneObjectPart obj, XmlTextReader reader) { - obj.LastOwnerID = ReadUUID(reader, "LastOwnerID"); + obj.LastOwnerID = Util.ReadUUID(reader, "LastOwnerID"); } private static void ProcessBaseMask(SceneObjectPart obj, XmlTextReader reader) @@ -654,16 +654,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessFlags(SceneObjectPart obj, XmlTextReader reader) { - string value = reader.ReadElementContentAsString("Flags", String.Empty); - // !!!!! to deal with flags without commas - if (value.Contains(" ") && !value.Contains(",")) - value = value.Replace(" ", ", "); - obj.Flags = (PrimFlags)Enum.Parse(typeof(PrimFlags), value); + obj.Flags = Util.ReadEnum(reader, "Flags"); } private static void ProcessCollisionSound(SceneObjectPart obj, XmlTextReader reader) { - obj.CollisionSound = ReadUUID(reader, "CollisionSound"); + obj.CollisionSound = Util.ReadUUID(reader, "CollisionSound"); } private static void ProcessCollisionSoundVolume(SceneObjectPart obj, XmlTextReader reader) @@ -690,7 +686,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization #region TaskInventoryXmlProcessors private static void ProcessTIAssetID(TaskInventoryItem item, XmlTextReader reader) { - item.AssetID = ReadUUID(reader, "AssetID"); + item.AssetID = Util.ReadUUID(reader, "AssetID"); } private static void ProcessTIBasePermissions(TaskInventoryItem item, XmlTextReader reader) @@ -705,7 +701,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessTICreatorID(TaskInventoryItem item, XmlTextReader reader) { - item.CreatorID = ReadUUID(reader, "CreatorID"); + item.CreatorID = Util.ReadUUID(reader, "CreatorID"); } private static void ProcessTICreatorData(TaskInventoryItem item, XmlTextReader reader) @@ -730,7 +726,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessTIGroupID(TaskInventoryItem item, XmlTextReader reader) { - item.GroupID = ReadUUID(reader, "GroupID"); + item.GroupID = Util.ReadUUID(reader, "GroupID"); } private static void ProcessTIGroupPermissions(TaskInventoryItem item, XmlTextReader reader) @@ -745,20 +741,20 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessTIItemID(TaskInventoryItem item, XmlTextReader reader) { - item.ItemID = ReadUUID(reader, "ItemID"); + item.ItemID = Util.ReadUUID(reader, "ItemID"); } private static void ProcessTIOldItemID(TaskInventoryItem item, XmlTextReader reader) { - ReadUUID(reader, "OldItemID"); + Util.ReadUUID(reader, "OldItemID"); // On deserialization, the old item id MUST BE UUID.Zero!!!!! // Setting this to the saved value will BREAK script persistence! - // item.OldItemID = ReadUUID(reader, "OldItemID"); + // item.OldItemID = Util.ReadUUID(reader, "OldItemID"); } private static void ProcessTILastOwnerID(TaskInventoryItem item, XmlTextReader reader) { - item.LastOwnerID = ReadUUID(reader, "LastOwnerID"); + item.LastOwnerID = Util.ReadUUID(reader, "LastOwnerID"); } private static void ProcessTIName(TaskInventoryItem item, XmlTextReader reader) @@ -773,7 +769,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessTIOwnerID(TaskInventoryItem item, XmlTextReader reader) { - item.OwnerID = ReadUUID(reader, "OwnerID"); + item.OwnerID = Util.ReadUUID(reader, "OwnerID"); } private static void ProcessTICurrentPermissions(TaskInventoryItem item, XmlTextReader reader) @@ -783,17 +779,17 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessTIParentID(TaskInventoryItem item, XmlTextReader reader) { - item.ParentID = ReadUUID(reader, "ParentID"); + item.ParentID = Util.ReadUUID(reader, "ParentID"); } private static void ProcessTIParentPartID(TaskInventoryItem item, XmlTextReader reader) { - item.ParentPartID = ReadUUID(reader, "ParentPartID"); + item.ParentPartID = Util.ReadUUID(reader, "ParentPartID"); } private static void ProcessTIPermsGranter(TaskInventoryItem item, XmlTextReader reader) { - item.PermsGranter = ReadUUID(reader, "PermsGranter"); + item.PermsGranter = Util.ReadUUID(reader, "PermsGranter"); } private static void ProcessTIPermsMask(TaskInventoryItem item, XmlTextReader reader) @@ -808,7 +804,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessTIOwnerChanged(TaskInventoryItem item, XmlTextReader reader) { - item.OwnerChanged = reader.ReadElementContentAsBoolean("OwnerChanged", String.Empty); + item.OwnerChanged = Util.ReadBoolean(reader); } #endregion @@ -922,7 +918,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessShpScale(PrimitiveBaseShape shp, XmlTextReader reader) { - shp.Scale = ReadVector(reader, "Scale"); + shp.Scale = Util.ReadVector(reader, "Scale"); } private static void ProcessShpState(PrimitiveBaseShape shp, XmlTextReader reader) @@ -932,25 +928,17 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessShpProfileShape(PrimitiveBaseShape shp, XmlTextReader reader) { - string value = reader.ReadElementContentAsString("ProfileShape", String.Empty); - // !!!!! to deal with flags without commas - if (value.Contains(" ") && !value.Contains(",")) - value = value.Replace(" ", ", "); - shp.ProfileShape = (ProfileShape)Enum.Parse(typeof(ProfileShape), value); + shp.ProfileShape = Util.ReadEnum(reader, "ProfileShape"); } private static void ProcessShpHollowShape(PrimitiveBaseShape shp, XmlTextReader reader) { - string value = reader.ReadElementContentAsString("HollowShape", String.Empty); - // !!!!! to deal with flags without commas - if (value.Contains(" ") && !value.Contains(",")) - value = value.Replace(" ", ", "); - shp.HollowShape = (HollowShape)Enum.Parse(typeof(HollowShape), value); + shp.HollowShape = Util.ReadEnum(reader, "HollowShape"); } private static void ProcessShpSculptTexture(PrimitiveBaseShape shp, XmlTextReader reader) { - shp.SculptTexture = ReadUUID(reader, "SculptTexture"); + shp.SculptTexture = Util.ReadUUID(reader, "SculptTexture"); } private static void ProcessShpSculptType(PrimitiveBaseShape shp, XmlTextReader reader) @@ -1045,17 +1033,17 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessShpFlexiEntry(PrimitiveBaseShape shp, XmlTextReader reader) { - shp.FlexiEntry = reader.ReadElementContentAsBoolean("FlexiEntry", String.Empty); + shp.FlexiEntry = Util.ReadBoolean(reader); } private static void ProcessShpLightEntry(PrimitiveBaseShape shp, XmlTextReader reader) { - shp.LightEntry = reader.ReadElementContentAsBoolean("LightEntry", String.Empty); + shp.LightEntry = Util.ReadBoolean(reader); } private static void ProcessShpSculptEntry(PrimitiveBaseShape shp, XmlTextReader reader) { - shp.SculptEntry = reader.ReadElementContentAsBoolean("SculptEntry", String.Empty); + shp.SculptEntry = Util.ReadBoolean(reader); } private static void ProcessShpMedia(PrimitiveBaseShape shp, XmlTextReader reader) @@ -1220,16 +1208,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization static void WriteFlags(XmlTextWriter writer, string name, string flagsStr, Dictionary options) { - // Older versions of serialization can't cope with commas - if (options.ContainsKey("version")) - { - float version = 0.5F; - float.TryParse(options["version"].ToString(), out version); - if (version < 0.5) - flagsStr = flagsStr.Replace(",", ""); - } - - writer.WriteElementString(name, flagsStr); + // Older versions of serialization can't cope with commas, so we eliminate the commas + writer.WriteElementString(name, flagsStr.Replace(",", "")); } static void WriteTaskInventory(XmlTextWriter writer, TaskInventoryDictionary tinv, Dictionary options, Scene scene) @@ -1459,66 +1439,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization return obj; } - static UUID ReadUUID(XmlTextReader reader, string name) - { - UUID id; - string idStr; - - reader.ReadStartElement(name); - - if (reader.Name == "Guid") - idStr = reader.ReadElementString("Guid"); - else // UUID - idStr = reader.ReadElementString("UUID"); - - UUID.TryParse(idStr, out id); - reader.ReadEndElement(); - - return id; - } - - static Vector3 ReadVector(XmlTextReader reader, string name) - { - Vector3 vec; - - reader.ReadStartElement(name); - vec.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // X or x - vec.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Y or y - vec.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Z or z - reader.ReadEndElement(); - - return vec; - } - - static Quaternion ReadQuaternion(XmlTextReader reader, string name) - { - Quaternion quat = new Quaternion(); - - reader.ReadStartElement(name); - while (reader.NodeType != XmlNodeType.EndElement) - { - switch (reader.Name.ToLower()) - { - case "x": - quat.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - case "y": - quat.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - case "z": - quat.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - case "w": - quat.W = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - } - } - - reader.ReadEndElement(); - - return quat; - } - static TaskInventoryDictionary ReadTaskInventory(XmlTextReader reader, string name) { TaskInventoryDictionary tinv = new TaskInventoryDictionary(); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs index f57cf98b37..b84298f2fa 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs @@ -121,13 +121,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests "Not exactly sure what this is asserting..."); // Delink part 2 - grp1.DelinkFromGroup(part2.LocalId); + SceneObjectGroup grp3 = grp1.DelinkFromGroup(part2.LocalId); if (debugtest) m_log.Debug("Group2: Prim2: OffsetPosition:" + part2.AbsolutePosition + ", OffsetRotation:" + part2.RotationOffset); Assert.That(grp1.Parts.Length, Is.EqualTo(1), "Group 1 still contained part2 after delink."); Assert.That(part2.AbsolutePosition == Vector3.Zero, "The absolute position should be zero"); + Assert.That(grp3.HasGroupChangedDueToDelink, Is.True); } [Test] @@ -325,7 +326,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneObjectGroup sog = new SceneObjectGroup(rootPart); sog.AddPart(linkPart); - scene.AddNewSceneObject(sog, true); + scene.AddNewSceneObject(sog, true); // In a test, we have to crank the backup handle manually. Normally this would be done by the timer invoked // scene backup thread. @@ -333,7 +334,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests // These changes should occur immediately without waiting for a backup pass SceneObjectGroup groupToDelete = sog.DelinkFromGroup(linkPart, false); + + Assert.That(groupToDelete.HasGroupChangedDueToDelink, Is.True); scene.DeleteSceneObject(groupToDelete, false); + Assert.That(groupToDelete.HasGroupChangedDueToDelink, Is.False); List storedObjects = scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID); diff --git a/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs b/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs index b6425f4c49..df571fa925 100644 --- a/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs +++ b/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs @@ -53,12 +53,15 @@ namespace OpenSim.Server.Handlers.Asset String.Empty); if (assetService == String.Empty) - throw new Exception("No AssetService in config file"); + throw new Exception("No LocalServiceModule in config file"); Object[] args = new Object[] { config }; m_AssetService = ServerUtils.LoadPlugin(assetService, args); + if (m_AssetService == null) + throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); + bool allowDelete = serverConfig.GetBoolean("AllowRemoteDelete", false); server.AddStreamHandler(new AssetServerGetHandler(m_AssetService)); diff --git a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs index ce72c78ad6..edb44ea357 100644 --- a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs +++ b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs @@ -153,7 +153,7 @@ namespace OpenSim.Server.Handlers.Asset } catch (Exception e) { - m_log.Debug("[XINVENTORY HANDLER]: Exception {0}", e); + m_log.DebugFormat("[XINVENTORY HANDLER]: Exception {0}", e); } return FailureResult(); @@ -605,6 +605,10 @@ namespace OpenSim.Server.Handlers.Asset ret["CreatorId"] = item.CreatorId.ToString(); else ret["CreatorId"] = String.Empty; + if (item.CreatorData != null) + ret["CreatorData"] = item.CreatorData; + else + ret["CreatorData"] = String.Empty; ret["CurrentPermissions"] = item.CurrentPermissions.ToString(); ret["Description"] = item.Description.ToString(); ret["EveryOnePermissions"] = item.EveryOnePermissions.ToString(); diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs index 3122382308..81ef225ca1 100644 --- a/OpenSim/Services/AssetService/AssetService.cs +++ b/OpenSim/Services/AssetService/AssetService.cs @@ -43,44 +43,51 @@ namespace OpenSim.Services.AssetService LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); + protected static AssetService m_RootInstance; + public AssetService(IConfigSource config) : base(config) { - MainConsole.Instance.Commands.AddCommand("kfs", false, - "show digest", - "show digest ", - "Show asset digest", HandleShowDigest); - - MainConsole.Instance.Commands.AddCommand("kfs", false, - "delete asset", - "delete asset ", - "Delete asset from database", HandleDeleteAsset); - - if (m_AssetLoader != null) + if (m_RootInstance == null) { - IConfig assetConfig = config.Configs["AssetService"]; - if (assetConfig == null) - throw new Exception("No AssetService configuration"); + m_RootInstance = this; - string loaderArgs = assetConfig.GetString("AssetLoaderArgs", - String.Empty); + MainConsole.Instance.Commands.AddCommand("kfs", false, + "show digest", + "show digest ", + "Show asset digest", HandleShowDigest); - bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true); + MainConsole.Instance.Commands.AddCommand("kfs", false, + "delete asset", + "delete asset ", + "Delete asset from database", HandleDeleteAsset); - if (assetLoaderEnabled) + if (m_AssetLoader != null) { - m_log.InfoFormat("[ASSET]: Loading default asset set from {0}", loaderArgs); - m_AssetLoader.ForEachDefaultXmlAsset(loaderArgs, - delegate(AssetBase a) - { - Store(a); - }); + IConfig assetConfig = config.Configs["AssetService"]; + if (assetConfig == null) + throw new Exception("No AssetService configuration"); + + string loaderArgs = assetConfig.GetString("AssetLoaderArgs", + String.Empty); + + bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true); + + if (assetLoaderEnabled) + { + m_log.InfoFormat("[ASSET]: Loading default asset set from {0}", loaderArgs); + m_AssetLoader.ForEachDefaultXmlAsset(loaderArgs, + delegate(AssetBase a) + { + Store(a); + }); + } + + m_log.Info("[ASSET SERVICE]: Local asset service enabled"); } - - m_log.Info("[ASSET SERVICE]: Local asset service enabled"); } } - public AssetBase Get(string id) + public virtual AssetBase Get(string id) { UUID assetID; @@ -93,12 +100,12 @@ namespace OpenSim.Services.AssetService return m_Database.GetAsset(assetID); } - public AssetBase GetCached(string id) + public virtual AssetBase GetCached(string id) { return Get(id); } - public AssetMetadata GetMetadata(string id) + public virtual AssetMetadata GetMetadata(string id) { UUID assetID; @@ -112,7 +119,7 @@ namespace OpenSim.Services.AssetService return null; } - public byte[] GetData(string id) + public virtual byte[] GetData(string id) { UUID assetID; @@ -123,7 +130,7 @@ namespace OpenSim.Services.AssetService return asset.Data; } - public bool Get(string id, Object sender, AssetRetrieved handler) + public virtual bool Get(string id, Object sender, AssetRetrieved handler) { //m_log.DebugFormat("[AssetService]: Get asset async {0}", id); @@ -141,7 +148,7 @@ namespace OpenSim.Services.AssetService return true; } - public string Store(AssetBase asset) + public virtual string Store(AssetBase asset) { //m_log.DebugFormat("[ASSET SERVICE]: Store asset {0} {1}", asset.Name, asset.ID); if (!m_Database.StoreAsset(asset)) @@ -157,7 +164,7 @@ namespace OpenSim.Services.AssetService return false; } - public bool Delete(string id) + public virtual bool Delete(string id) { m_log.DebugFormat("[ASSET SERVICE]: Deleting asset {0}", id); UUID assetID; diff --git a/OpenSim/Services/HypergridService/HGAssetService.cs b/OpenSim/Services/HypergridService/HGAssetService.cs new file mode 100644 index 0000000000..a82d0d191f --- /dev/null +++ b/OpenSim/Services/HypergridService/HGAssetService.cs @@ -0,0 +1,145 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Xml; + +using Nini.Config; +using log4net; +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Serialization.External; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Services.AssetService; + +namespace OpenSim.Services.HypergridService +{ + /// + /// Hypergrid asset service. It serves the IAssetService interface, + /// but implements it in ways that are appropriate for inter-grid + /// asset exchanges. + /// + public class HGAssetService : OpenSim.Services.AssetService.AssetService, IAssetService + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private string m_ProfileServiceURL; + private IUserAccountService m_UserAccountService; + + private UserAccountCache m_Cache; + + public HGAssetService(IConfigSource config) : base(config) + { + m_log.Debug("[HGAsset Service]: Starting"); + IConfig assetConfig = config.Configs["HGAssetService"]; + if (assetConfig == null) + throw new Exception("No HGAssetService configuration"); + + string userAccountsDll = assetConfig.GetString("UserAccountsService", string.Empty); + if (userAccountsDll == string.Empty) + throw new Exception("Please specify UserAccountsService in HGAssetService configuration"); + + Object[] args = new Object[] { config }; + m_UserAccountService = ServerUtils.LoadPlugin(userAccountsDll, args); + if (m_UserAccountService == null) + throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll)); + + m_ProfileServiceURL = assetConfig.GetString("ProfileServerURI", string.Empty); + + m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); + } + + #region IAssetService overrides + public override AssetBase Get(string id) + { + AssetBase asset = base.Get(id); + + if (asset == null) + return null; + + if (asset.Metadata.Type == (sbyte)AssetType.Object) + asset.Data = AdjustIdentifiers(asset.Data); ; + + AdjustIdentifiers(asset.Metadata); + + return asset; + } + + public override AssetMetadata GetMetadata(string id) + { + AssetMetadata meta = base.GetMetadata(id); + + if (meta == null) + return null; + + AdjustIdentifiers(meta); + + return meta; + } + + public override byte[] GetData(string id) + { + byte[] data = base.GetData(id); + + if (data == null) + return null; + + return AdjustIdentifiers(data); + } + + //public virtual bool Get(string id, Object sender, AssetRetrieved handler) + + public override bool Delete(string id) + { + // NOGO + return false; + } + + #endregion + + protected void AdjustIdentifiers(AssetMetadata meta) + { + UserAccount creator = m_Cache.GetUser(meta.CreatorID); + if (creator != null) + meta.CreatorID = m_ProfileServiceURL + "/" + meta.CreatorID + ";" + creator.FirstName + " " + creator.LastName; + } + + protected byte[] AdjustIdentifiers(byte[] data) + { + string xml = Utils.BytesToString(data); + return Utils.StringToBytes(ExternalRepresentationUtils.RewriteSOP(xml, m_ProfileServiceURL, m_Cache, UUID.Zero)); + } + + } + +} diff --git a/OpenSim/Services/InventoryService/HGInventoryService.cs b/OpenSim/Services/HypergridService/HGInventoryService.cs similarity index 84% rename from OpenSim/Services/InventoryService/HGInventoryService.cs rename to OpenSim/Services/HypergridService/HGInventoryService.cs index d62c0089a2..9ee1ae4c5f 100644 --- a/OpenSim/Services/InventoryService/HGInventoryService.cs +++ b/OpenSim/Services/HypergridService/HGInventoryService.cs @@ -33,11 +33,20 @@ using Nini.Config; using System.Reflection; using OpenSim.Services.Base; using OpenSim.Services.Interfaces; +using OpenSim.Services.InventoryService; using OpenSim.Data; using OpenSim.Framework; +using OpenSim.Server.Base; -namespace OpenSim.Services.InventoryService +namespace OpenSim.Services.HypergridService { + /// + /// Hypergrid inventory service. It serves the IInventoryService interface, + /// but implements it in ways that are appropriate for inter-grid + /// inventory exchanges. Specifically, it does not performs deletions + /// and it responds to GetRootFolder requests with the ID of the + /// Suitcase folder, not the actual "My Inventory" folder. + /// public class HGInventoryService : XInventoryService, IInventoryService { private static readonly ILog m_log = @@ -46,9 +55,16 @@ namespace OpenSim.Services.InventoryService protected new IXInventoryData m_Database; + private string m_ProfileServiceURL; + private IUserAccountService m_UserAccountService; + + private UserAccountCache m_Cache; + public HGInventoryService(IConfigSource config) : base(config) { + m_log.Debug("[HGInventory Service]: Starting"); + string dllName = String.Empty; string connString = String.Empty; //string realm = "Inventory"; // OSG version doesn't use this @@ -68,12 +84,25 @@ namespace OpenSim.Services.InventoryService // // Try reading the [InventoryService] section, if it exists // - IConfig authConfig = config.Configs["InventoryService"]; - if (authConfig != null) + IConfig invConfig = config.Configs["HGInventoryService"]; + if (invConfig != null) { - dllName = authConfig.GetString("StorageProvider", dllName); - connString = authConfig.GetString("ConnectionString", connString); + dllName = invConfig.GetString("StorageProvider", dllName); + connString = invConfig.GetString("ConnectionString", connString); + // realm = authConfig.GetString("Realm", realm); + string userAccountsDll = invConfig.GetString("UserAccountsService", string.Empty); + if (userAccountsDll == string.Empty) + throw new Exception("Please specify UserAccountsService in HGInventoryService configuration"); + + Object[] args = new Object[] { config }; + m_UserAccountService = ServerUtils.LoadPlugin(userAccountsDll, args); + if (m_UserAccountService == null) + throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll)); + + m_ProfileServiceURL = invConfig.GetString("ProfileServerURI", string.Empty); + + m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); } // @@ -282,9 +311,18 @@ namespace OpenSim.Services.InventoryService //{ //} - //public InventoryItemBase GetItem(InventoryItemBase item) - //{ - //} + public override InventoryItemBase GetItem(InventoryItemBase item) + { + InventoryItemBase it = base.GetItem(item); + + UserAccount user = m_Cache.GetUser(it.CreatorId); + + // Adjust the creator data + if (user != null && it != null && (it.CreatorData == null || it.CreatorData == string.Empty)) + it.CreatorData = m_ProfileServiceURL + "/" + it.CreatorId + ";" + user.FirstName + " " + user.LastName; + + return it; + } //public InventoryFolderBase GetFolder(InventoryFolderBase folder) //{ diff --git a/OpenSim/Services/HypergridService/UserAccountCache.cs b/OpenSim/Services/HypergridService/UserAccountCache.cs new file mode 100644 index 0000000000..3e9aea10eb --- /dev/null +++ b/OpenSim/Services/HypergridService/UserAccountCache.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +using log4net; +using OpenMetaverse; + +using OpenSim.Services.Interfaces; + +namespace OpenSim.Services.HypergridService +{ + public class UserAccountCache : IUserAccountService + { + private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours! + + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + private ExpiringCache m_UUIDCache; + + private IUserAccountService m_UserAccountService; + + private static UserAccountCache m_Singleton; + + public static UserAccountCache CreateUserAccountCache(IUserAccountService u) + { + if (m_Singleton == null) + m_Singleton = new UserAccountCache(u); + + return m_Singleton; + } + + private UserAccountCache(IUserAccountService u) + { + m_UUIDCache = new ExpiringCache(); + m_UserAccountService = u; + } + + public void Cache(UUID userID, UserAccount account) + { + // Cache even null accounts + m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS); + + //m_log.DebugFormat("[USER CACHE]: cached user {0}", userID); + } + + public UserAccount Get(UUID userID, out bool inCache) + { + UserAccount account = null; + inCache = false; + if (m_UUIDCache.TryGetValue(userID, out account)) + { + //m_log.DebugFormat("[USER CACHE]: Account {0} {1} found in cache", account.FirstName, account.LastName); + inCache = true; + return account; + } + + return null; + } + + public UserAccount GetUser(string id) + { + UUID uuid = UUID.Zero; + UUID.TryParse(id, out uuid); + bool inCache = false; + UserAccount account = Get(uuid, out inCache); + if (!inCache) + { + account = m_UserAccountService.GetUserAccount(UUID.Zero, uuid); + Cache(uuid, account); + } + + return account; + } + + #region IUserAccountService + public UserAccount GetUserAccount(UUID scopeID, UUID userID) + { + return GetUser(userID.ToString()); + } + + public UserAccount GetUserAccount(UUID scopeID, string FirstName, string LastName) + { + return null; + } + + public UserAccount GetUserAccount(UUID scopeID, string Email) + { + return null; + } + + public List GetUserAccounts(UUID scopeID, string query) + { + return null; + } + + public bool StoreUserAccount(UserAccount data) + { + return false; + } + #endregion + + } + +} diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index b26cd6e149..335c7e709b 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -769,6 +769,7 @@ namespace OpenSim.Services.LLLoginService if (account.ServiceURLs == null) return; + // Old style: get the service keys from the DB foreach (KeyValuePair kvp in account.ServiceURLs) { if (kvp.Value == null || (kvp.Value != null && kvp.Value.ToString() == string.Empty)) @@ -780,6 +781,21 @@ namespace OpenSim.Services.LLLoginService aCircuit.ServiceURLs[kvp.Key] = kvp.Value; } } + + // New style: service keys start with SRV_; override the previous + string[] keys = m_LoginServerConfig.GetKeys(); + + if (keys.Length > 0) + { + IEnumerable serviceKeys = keys.Where(value => value.StartsWith("SRV_")); + foreach (string serviceKey in serviceKeys) + { + string keyName = serviceKey.Replace("SRV_", ""); + aCircuit.ServiceURLs[keyName] = m_LoginServerConfig.GetString(serviceKey, string.Empty); + m_log.DebugFormat("[LLLOGIN SERVICE]: found new key {0} {1}", keyName, aCircuit.ServiceURLs[keyName]); + } + } + } private bool LaunchAgentDirectly(ISimulationService simConnector, GridRegion region, AgentCircuitData aCircuit, out string reason) diff --git a/bin/OpenSim.Grid.GridServer.addin.xml b/bin/OpenSim.Grid.GridServer.addin.xml deleted file mode 100644 index 85742a16d2..0000000000 --- a/bin/OpenSim.Grid.GridServer.addin.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/bin/OpenSim.Grid.GridServer.exe.config b/bin/OpenSim.Grid.GridServer.exe.config deleted file mode 100644 index efc486f137..0000000000 --- a/bin/OpenSim.Grid.GridServer.exe.config +++ /dev/null @@ -1,28 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/OpenSim.Grid.MessagingServer.exe.config b/bin/OpenSim.Grid.MessagingServer.exe.config deleted file mode 100644 index 481ce4b978..0000000000 --- a/bin/OpenSim.Grid.MessagingServer.exe.config +++ /dev/null @@ -1,28 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/OpenSim.Grid.ScriptServer.exe.config b/bin/OpenSim.Grid.ScriptServer.exe.config deleted file mode 100644 index 5cae2b00eb..0000000000 --- a/bin/OpenSim.Grid.ScriptServer.exe.config +++ /dev/null @@ -1,28 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/OpenSim.Grid.UserServer.exe.config b/bin/OpenSim.Grid.UserServer.exe.config deleted file mode 100644 index 315e69d6d1..0000000000 --- a/bin/OpenSim.Grid.UserServer.exe.config +++ /dev/null @@ -1,28 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/OpenSim.exe.config b/bin/OpenSim.exe.config index 3c7adf5419..eece04092f 100755 --- a/bin/OpenSim.exe.config +++ b/bin/OpenSim.exe.config @@ -13,6 +13,8 @@ + + diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index e1627c0534..dbac73b277 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -21,7 +21,7 @@ ; * [[@]/][:] ; * [Startup] -ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003/OpenSim.Server.Handlers.dll:XInventoryInConnector,8002/OpenSim.Server.Handlers.dll:FreeswitchServerConnector,8003/OpenSim.Server.Handlers.dll:GridServiceConnector,8002/OpenSim.Server.Handlers.dll:GridInfoServerInConnector,8003/OpenSim.Server.Handlers.dll:AuthenticationServiceConnector,8002/OpenSim.Server.Handlers.dll:OpenIdServerConnector,8003/OpenSim.Server.Handlers.dll:AvatarServiceConnector,8002/OpenSim.Server.Handlers.dll:LLLoginServiceInConnector,8003/OpenSim.Server.Handlers.dll:PresenceServiceConnector,8003/OpenSim.Server.Handlers.dll:UserAccountServiceConnector,8003/OpenSim.Server.Handlers.dll:GridUserServiceConnector,8003/OpenSim.Server.Handlers.dll:FriendsServiceConnector,8002/OpenSim.Server.Handlers.dll:GatekeeperServiceInConnector,8002/OpenSim.Server.Handlers.dll:UserAgentServerConnector,HGInventoryService@8002/OpenSim.Server.Handlers.dll:XInventoryInConnector,8002/OpenSim.Server.Handlers.dll:AssetServiceConnector,8002/OpenSim.Server.Handlers.dll:HeloServiceInConnector" +ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003/OpenSim.Server.Handlers.dll:XInventoryInConnector,8002/OpenSim.Server.Handlers.dll:FreeswitchServerConnector,8003/OpenSim.Server.Handlers.dll:GridServiceConnector,8002/OpenSim.Server.Handlers.dll:GridInfoServerInConnector,8003/OpenSim.Server.Handlers.dll:AuthenticationServiceConnector,8002/OpenSim.Server.Handlers.dll:OpenIdServerConnector,8003/OpenSim.Server.Handlers.dll:AvatarServiceConnector,8002/OpenSim.Server.Handlers.dll:LLLoginServiceInConnector,8003/OpenSim.Server.Handlers.dll:PresenceServiceConnector,8003/OpenSim.Server.Handlers.dll:UserAccountServiceConnector,8003/OpenSim.Server.Handlers.dll:GridUserServiceConnector,8003/OpenSim.Server.Handlers.dll:FriendsServiceConnector,8002/OpenSim.Server.Handlers.dll:GatekeeperServiceInConnector,8002/OpenSim.Server.Handlers.dll:UserAgentServerConnector,HGInventoryService@8002/OpenSim.Server.Handlers.dll:XInventoryInConnector,HGAssetService@8002/OpenSim.Server.Handlers.dll:AssetServiceConnector,8002/OpenSim.Server.Handlers.dll:HeloServiceInConnector" ; * This is common for all services, it's the network setup for the entire ; * server instance, if none if specified above @@ -154,10 +154,12 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ; Defaults for the users, if none is specified in the useraccounts table entry (ServiceURLs) ; CHANGE THIS - HomeURI = "http://127.0.0.1:8002" - GatekeeperURI = "http://127.0.0.1:8002" - InventoryServerURI = "http://127.0.0.1:8002" - AssetServerURI = "http://127.0.0.1:8002" + GatekeeperURI = "http://127.0.0.1:8002" + + SRV_HomeURI = "http://127.0.0.1:8002" + SRV_InventoryServerURI = "http://127.0.0.1:8002" + SRV_AssetServerURI = "http://127.0.0.1:8002" + SRV_ProfileServerURI = "http://127.0.0.1:8002" [GridInfoService] ; These settings are used to return information on a get_grid_info call. @@ -169,7 +171,7 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ; See http://opensimulator.org/wiki/GridInfo ; login uri: for grid this is the login server URI - login = http://127.0.0.1:9000/ + login = http://127.0.0.1:8002/ ; long grid name: the long name of your grid gridname = "the lost continent of hippo" @@ -183,7 +185,7 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ; helper uri: optional: if it exists if will be used to tell the client to use ; this for all economy related things - ;economy = http://127.0.0.1:9000/ + ;economy = http://127.0.0.1:8002/ ; web page of grid: optional: page providing further information about your grid ;about = http://127.0.0.1/about/ @@ -241,4 +243,15 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ; * [HGInventoryService] ; For the InventoryServiceInConnector - LocalServiceModule = "OpenSim.Services.InventoryService.dll:HGInventoryService" + LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInventoryService" + UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService" + ProfileServerURI = "http://127.0.0.1:8002/user" + +; * The interface that local users get when they are in other grids. +; * This restricts the access that the rest of the world has to +; * the assets of this world. +; * +[HGAssetService] + LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGAssetService" + UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService" + ProfileServerURI = "http://127.0.0.1:8002/user" diff --git a/bin/config-include/GridCommon.ini.example b/bin/config-include/GridCommon.ini.example index cb771b8d52..762b09a30e 100644 --- a/bin/config-include/GridCommon.ini.example +++ b/bin/config-include/GridCommon.ini.example @@ -78,6 +78,14 @@ ; FriendsServerURI = "http://mygridserver.com:8003" +[HGInventoryAccessModule] + ; + ; === HG ONLY === + ; Change this to your profile server + ; accessible from other grids + ; + ProfileServerURI = "http://mygridserver.com:8002/profiles" + [Modules] ;; Choose 0 or 1 cache modules, and the corresponding config file, if it exists. ;; Copy the config .example file into your own .ini file and change configs there diff --git a/bin/config-include/StandaloneCommon.ini.example b/bin/config-include/StandaloneCommon.ini.example index 1fcf043ea2..58059f52a1 100644 --- a/bin/config-include/StandaloneCommon.ini.example +++ b/bin/config-include/StandaloneCommon.ini.example @@ -25,6 +25,15 @@ DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll" AssetLoaderArgs = "assets/AssetSets.xml" +[HGInventoryService] + ProfileServerURI = "http://127.0.0.1:9000/profiles" + +[HGAssetService] + ProfileServerURI = "http://127.0.0.1:9000/profiles" + +[HGInventoryAccessModule] + ProfileServerURI = "http://127.0.0.1:9000/profiles" + [Modules] ;; Choose 0 or 1 cache modules, and the corresponding config file, if it exists. ;; Copy the config .example file into your own .ini file and change configs there @@ -68,11 +77,12 @@ [LoginService] WelcomeMessage = "Welcome, Avatar!" - - HomeURI = "http://127.0.0.1:9000" GatekeeperURI = "http://127.0.0.1:9000" - InventoryServerURI = "http://127.0.0.1:9000" - AssetServerURI = "http://127.0.0.1:9000" + + SRV_HomeURI = "http://127.0.0.1:9000" + SRV_InventoryServerURI = "http://127.0.0.1:9000" + SRV_AssetServerURI = "http://127.0.0.1:9000" + SRV_ProfileServerURI = "http://127.0.0.1:9000" [GatekeeperService] ExternalName = "http://127.0.0.1:9000" diff --git a/bin/config-include/StandaloneHypergrid.ini b/bin/config-include/StandaloneHypergrid.ini index f164d33e1e..68aa7397fc 100644 --- a/bin/config-include/StandaloneHypergrid.ini +++ b/bin/config-include/StandaloneHypergrid.ini @@ -128,8 +128,14 @@ ;; This greatly restricts the inventory operations while in other grids [HGInventoryService] ; For the InventoryServiceInConnector - LocalServiceModule = "OpenSim.Services.InventoryService.dll:HGInventoryService" + LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInventoryService" + UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService" +;; The interface that local users get when they are in other grids +;; This restricts/filters the asset operations from the outside +[HGAssetService] + LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGAssetService" + UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService" ;; This should always be the very last thing on this file [Includes] diff --git a/prebuild.xml b/prebuild.xml index f08d0d3908..a302d5ff4a 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -175,6 +175,34 @@ + + + + ../../../bin/ + + + + + ../../../bin/ + + + + ../../../bin/ + + + + + + + + + + + + + + + @@ -194,6 +222,7 @@ + @@ -661,35 +690,6 @@ - - - - ../../../bin/ - - - - - ../../../bin/ - - - - ../../../bin/ - - - - - - - - - - - - - - - - @@ -1284,10 +1284,13 @@ + + +