/// <summary> /// Create a test user with a standard inventory /// </summary> /// <param name="commsManager"></param> /// <param name="userId">Explicit user id to use for user creation</param> /// <returns></returns> public static CachedUserInfo CreateUserWithInventory(CommunicationsManager commsManager, UUID userId) { LocalUserServices lus = (LocalUserServices)commsManager.UserService; lus.AddUser("Bill", "Bailey", "troll", "*****@*****.**", 1000, 1000, userId); CachedUserInfo userInfo = commsManager.UserProfileCacheService.GetUserDetails(userId); userInfo.FetchInventory(); return(userInfo); }
/// <summary> /// Test replication of an archive path to the user's inventory. /// </summary> //[Test] public void TestReplicateArchivePathToUserInventory() { TestHelper.InMethod(); Scene scene = SceneSetupHelpers.SetupScene(false); CommunicationsManager commsManager = scene.CommsManager; CachedUserInfo userInfo = UserProfileTestUtils.CreateUserWithInventory(commsManager); userInfo.FetchInventory(); for (int i = 0; i < 50; i++) { if (userInfo.HasReceivedInventory == true) { break; } Thread.Sleep(200); } Assert.That(userInfo.HasReceivedInventory, Is.True, "FetchInventory timed out (10 seconds)"); Dictionary <string, InventoryFolderImpl> foldersCreated = new Dictionary <string, InventoryFolderImpl>(); List <InventoryNodeBase> nodesLoaded = new List <InventoryNodeBase>(); string folder1Name = "a"; string folder2Name = "b"; string itemName = "c.lsl"; string folder1ArchiveName = string.Format( "{0}{1}{2}", folder1Name, ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, UUID.Random()); string folder2ArchiveName = string.Format( "{0}{1}{2}", folder2Name, ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, UUID.Random()); string itemArchivePath = string.Format( "{0}{1}/{2}/{3}", ArchiveConstants.INVENTORY_PATH, folder1ArchiveName, folder2ArchiveName, itemName); new InventoryArchiveReadRequest(userInfo, null, (Stream)null, null, null) .ReplicateArchivePathToUserInventory(itemArchivePath, false, userInfo.RootFolder, foldersCreated, nodesLoaded); InventoryFolderImpl folder1 = userInfo.RootFolder.FindFolderByPath("a"); Assert.That(folder1, Is.Not.Null, "Could not find folder a"); InventoryFolderImpl folder2 = folder1.FindFolderByPath("b"); Assert.That(folder2, Is.Not.Null, "Could not find folder b"); }
/// <summary> /// /// </summary> /// <param name="msg"></param> private void OnGridInstantMessage(GridInstantMessage msg) { // Check if this is ours to handle // m_log.Info("OnFridInstantMessage"); if (msg.dialog != (byte)InstantMessageDialog.InventoryOffered) { return; } if (msg.binaryBucket.Length < 17) // Invalid { return; } Scene scene = FindClientScene(new UUID(msg.toAgentID)); // Find agent to deliver to // ScenePresence user = scene.GetScenePresence(new UUID(msg.toAgentID)); if (user == null) // Shouldn't happen { m_log.Debug("[INVENTORY TRANSFER] Can't find recipient"); return; } CachedUserInfo userInfo = scene.CommsManager.UserProfileCacheService. GetUserDetails(user.ControllingClient.AgentId); if (userInfo == null) { m_log.Debug("[INVENTORY TRANSFER] Can't find user info of recipient"); return; } AssetType assetType = (AssetType)msg.binaryBucket[0]; if (AssetType.Folder == assetType) { UUID folderID = new UUID(msg.binaryBucket, 1); InventoryFolderBase folder = new InventoryFolderBase(); folder.ID = folderID; folder.Owner = user.ControllingClient.AgentId; // Fetch from database // if (!userInfo.QueryFolder(folder)) { m_log.Debug("[INVENTORY TRANSFER] Can't find folder to give"); return; } // Get folder info // InventoryFolderImpl folderInfo = userInfo.RootFolder.FindFolder(folder.ID); if (folderInfo == null) { m_log.Debug("[INVENTORY TRANSFER] Can't retrieve folder to give"); return; } user.ControllingClient.SendBulkUpdateInventory(folderInfo); // This unelegant, slow kludge is to reload the folders and // items. Since a folder give can transfer subfolders and // items, this is the easiest way to pull that stuff in // userInfo.DropInventory(); userInfo.FetchInventory(); // Deliver message // user.ControllingClient.SendInstantMessage(msg); } else { UUID itemID = new UUID(msg.binaryBucket, 1); InventoryItemBase item = new InventoryItemBase(); item.ID = itemID; item.Owner = user.ControllingClient.AgentId; // Fetch from database // if (!userInfo.QueryItem(item)) { m_log.Debug("[INVENTORY TRANSFER] Can't find item to give"); return; } // Get item info // item = userInfo.RootFolder.FindItem(item.ID); if (item == null) { m_log.Debug("[INVENTORY TRANSFER] Can't retrieve item to give"); return; } // Update item to viewer (makes it appear in proper folder) // user.ControllingClient.SendBulkUpdateInventory(item); // Deliver message // user.ControllingClient.SendInstantMessage(msg); } }
/// <summary> /// Execute the request /// </summary> /// <returns> /// A list of the inventory nodes loaded. If folders were loaded then only the root folders are /// returned /// </returns> public List <InventoryNodeBase> Execute() { string filePath = "ERROR"; int successfulAssetRestores = 0; int failedAssetRestores = 0; int successfulItemRestores = 0; List <InventoryNodeBase> nodesLoaded = new List <InventoryNodeBase>(); if (!m_userInfo.HasReceivedInventory) { // If the region server has access to the user admin service (by which users are created), // then we'll assume that it's okay to fiddle with the user's inventory even if they are not on the // server. // // FIXME: FetchInventory should probably be assumed to by async anyway, since even standalones might // use a remote inventory service, though this is vanishingly rare at the moment. if (null == m_commsManager.UserAdminService) { m_log.ErrorFormat( "[INVENTORY ARCHIVER]: Have not yet received inventory info for user {0} {1}", m_userInfo.UserProfile.Name, m_userInfo.UserProfile.ID); return(nodesLoaded); } else { m_userInfo.FetchInventory(); } } InventoryFolderImpl rootDestinationFolder = m_userInfo.RootFolder.FindFolderByPath(m_invPath); if (null == rootDestinationFolder) { // Possibly provide an option later on to automatically create this folder if it does not exist m_log.ErrorFormat("[INVENTORY ARCHIVER]: Inventory path {0} does not exist", m_invPath); return(nodesLoaded); } archive = new TarArchiveReader(m_loadStream); // In order to load identically named folders, we need to keep track of the folders that we have already // created Dictionary <string, InventoryFolderImpl> foldersCreated = new Dictionary <string, InventoryFolderImpl>(); byte[] data; TarArchiveReader.TarEntryType entryType; while ((data = archive.ReadEntry(out filePath, out entryType)) != null) { if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) { if (LoadAsset(filePath, data)) { successfulAssetRestores++; } else { failedAssetRestores++; } } else if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH)) { InventoryFolderImpl foundFolder = ReplicateArchivePathToUserInventory( filePath, TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType, rootDestinationFolder, foldersCreated, nodesLoaded); if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY != entryType) { InventoryItemBase item = UserInventoryItemSerializer.Deserialize(data); // Don't use the item ID that's in the file item.ID = UUID.Random(); UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_commsManager); if (UUID.Zero != ospResolvedId) { item.CreatorIdAsUuid = ospResolvedId; } item.Owner = m_userInfo.UserProfile.ID; // Reset folder ID to the one in which we want to load it item.Folder = foundFolder.ID; m_userInfo.AddItem(item); successfulItemRestores++; // If we're loading an item directly into the given destination folder then we need to record // it separately from any loaded root folders if (rootDestinationFolder == foundFolder) { nodesLoaded.Add(item); } } } } archive.Close(); m_log.DebugFormat("[INVENTORY ARCHIVER]: Restored {0} assets", successfulAssetRestores); m_log.InfoFormat("[INVENTORY ARCHIVER]: Restored {0} items", successfulItemRestores); return(nodesLoaded); }
public void TestSaveIarV0p1() { TestHelper.InMethod(); //log4net.Config.XmlConfigurator.Configure(); InventoryArchiverModule archiverModule = new InventoryArchiverModule(); Scene scene = SceneSetupHelpers.SetupScene(false); SceneSetupHelpers.SetupSceneModules(scene, archiverModule); CommunicationsManager cm = scene.CommsManager; // Create user string userFirstName = "Jock"; string userLastName = "Stirrup"; UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); cm.UserAdminService.AddUser(userFirstName, userLastName, string.Empty, string.Empty, 1000, 1000, userId); CachedUserInfo userInfo = cm.UserProfileCacheService.GetUserDetails(userId); userInfo.FetchInventory(); // Create asset SceneObjectGroup object1; SceneObjectPart part1; { string partName = "My Little Dog Object"; UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); Vector3 groupPosition = new Vector3(10, 20, 30); Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); Vector3 offsetPosition = new Vector3(5, 10, 15); part1 = new SceneObjectPart( ownerId, shape, groupPosition, rotationOffset, offsetPosition); part1.Name = partName; object1 = new SceneObjectGroup(part1); scene.AddNewSceneObject(object1, false); } UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); AssetBase asset1 = new AssetBase(); asset1.FullID = asset1Id; asset1.Data = Encoding.ASCII.GetBytes(SceneObjectSerializer.ToXml2Format(object1)); cm.AssetCache.AddAsset(asset1); // Create item UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); InventoryItemBase item1 = new InventoryItemBase(); item1.Name = "My Little Dog"; item1.AssetID = asset1.FullID; item1.ID = item1Id; item1.Folder = userInfo.RootFolder.FindFolderByPath("Objects").ID; scene.AddInventoryItem(userId, item1); MemoryStream archiveWriteStream = new MemoryStream(); archiverModule.OnInventoryArchiveSaved += SaveCompleted; lock (this) { archiverModule.ArchiveInventory(userFirstName, userLastName, "Objects", archiveWriteStream); AssetServerBase assetServer = (AssetServerBase)scene.CommsManager.AssetCache.AssetServer; while (assetServer.HasWaitingRequests()) { assetServer.ProcessNextRequest(); } Monitor.Wait(this, 60000); } byte[] archive = archiveWriteStream.ToArray(); MemoryStream archiveReadStream = new MemoryStream(archive); TarArchiveReader tar = new TarArchiveReader(archiveReadStream); InventoryFolderImpl objectsFolder = userInfo.RootFolder.FindFolderByPath("Objects"); //bool gotControlFile = false; bool gotObject1File = false; //bool gotObject2File = false; string expectedObject1FilePath = string.Format( "{0}{1}/{2}_{3}.xml", ArchiveConstants.INVENTORY_PATH, string.Format( "Objects{0}{1}", ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, objectsFolder.ID), item1.Name, item1Id); /* * string expectedObject2FileName = string.Format( * "{0}_{1:000}-{2:000}-{3:000}__{4}.xml", * part2.Name, * Math.Round(part2.GroupPosition.X), Math.Round(part2.GroupPosition.Y), Math.Round(part2.GroupPosition.Z), * part2.UUID); */ string filePath; TarArchiveReader.TarEntryType tarEntryType; while (tar.ReadEntry(out filePath, out tarEntryType) != null) { Console.WriteLine("Got {0}", filePath); /* * if (ArchiveConstants.CONTROL_FILE_PATH == filePath) * { * gotControlFile = true; * } */ if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH) && filePath.EndsWith(".xml")) { //string fileName = filePath.Remove(0, "Objects/".Length); //if (fileName.StartsWith(part1.Name)) //{ Assert.That(filePath, Is.EqualTo(expectedObject1FilePath)); gotObject1File = true; //} //else if (fileName.StartsWith(part2.Name)) //{ // Assert.That(fileName, Is.EqualTo(expectedObject2FileName)); // gotObject2File = true; //} } } //Assert.That(gotControlFile, Is.True, "No control file in archive"); Assert.That(gotObject1File, Is.True, "No item1 file in archive"); //Assert.That(gotObject2File, Is.True, "No object2 file in archive"); // TODO: Test presence of more files and contents of files. }
/// <summary> /// Execute the inventory write request /// </summary> public void Execute() { InventoryFolderImpl inventoryFolder = null; InventoryItemBase inventoryItem = null; if (!m_userInfo.HasReceivedInventory) { // If the region server has access to the user admin service (by which users are created), // then we'll assume that it's okay to fiddle with the user's inventory even if they are not on the // server. // // FIXME: FetchInventory should probably be assumed to by async anyway, since even standalones might // use a remote inventory service, though this is vanishingly rare at the moment. if (null == m_module.CommsManager.UserAdminService) { m_log.ErrorFormat( "[INVENTORY ARCHIVER]: Have not yet received inventory info for user {0} {1}", m_userInfo.UserProfile.Name, m_userInfo.UserProfile.ID); return; } else { m_userInfo.FetchInventory(); } } bool foundStar = false; // Eliminate double slashes and any leading / on the path. This might be better done within InventoryFolderImpl // itself (possibly at a small loss in efficiency). string[] components = m_invPath.Split(new string[] { InventoryFolderImpl.PATH_DELIMITER }, StringSplitOptions.RemoveEmptyEntries); int maxComponentIndex = components.Length - 1; // If the path terminates with a STAR then later on we want to archive all nodes in the folder but not the // folder itself. This may get more sophisicated later on if (maxComponentIndex >= 0 && components[maxComponentIndex] == STAR_WILDCARD) { foundStar = true; maxComponentIndex--; } m_invPath = String.Empty; for (int i = 0; i <= maxComponentIndex; i++) { m_invPath += components[i] + InventoryFolderImpl.PATH_DELIMITER; } // Annoyingly Split actually returns the original string if the input string consists only of delimiters // Therefore if we still start with a / after the split, then we need the root folder if (m_invPath.Length == 0) { inventoryFolder = m_userInfo.RootFolder; } else { m_invPath = m_invPath.Remove(m_invPath.LastIndexOf(InventoryFolderImpl.PATH_DELIMITER)); inventoryFolder = m_userInfo.RootFolder.FindFolderByPath(m_invPath); } // The path may point to an item instead if (inventoryFolder == null) { inventoryItem = m_userInfo.RootFolder.FindItemByPath(m_invPath); } m_archiveWriter = new TarArchiveWriter(m_saveStream); if (null == inventoryFolder) { if (null == inventoryItem) { // We couldn't find the path indicated m_saveStream.Close(); m_module.TriggerInventoryArchiveSaved( false, m_userInfo, m_invPath, m_saveStream, new Exception(string.Format("Could not find inventory entry at path {0}", m_invPath))); return; } else { m_log.DebugFormat( "[INVENTORY ARCHIVER]: Found item {0} {1} at {2}", inventoryItem.Name, inventoryItem.ID, m_invPath); SaveInvItem(inventoryItem, ArchiveConstants.INVENTORY_PATH); } } else { m_log.DebugFormat( "[INVENTORY ARCHIVER]: Found folder {0} {1} at {2}", inventoryFolder.Name, inventoryFolder.ID, m_invPath); //recurse through all dirs getting dirs and files SaveInvFolder(inventoryFolder, ArchiveConstants.INVENTORY_PATH, !foundStar); } SaveUsers(); new AssetsRequest( new AssetsArchiver(m_archiveWriter), m_assetUuids.Keys, m_module.AssetService, ReceivedAllAssets).Execute(); }
/// <summary> /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where /// no account exists with the creator name /// </summary> //[Test] public void TestLoadIarV0_1TempProfiles() { TestHelper.InMethod(); log4net.Config.XmlConfigurator.Configure(); string userFirstName = "Dennis"; string userLastName = "Menace"; UUID userUuid = UUID.Parse("00000000-0000-0000-0000-000000000aaa"); string user2FirstName = "Walter"; string user2LastName = "Mitty"; string itemName = "b.lsl"; string archiveItemName = string.Format("{0}{1}{2}", itemName, "_", UUID.Random()); MemoryStream archiveWriteStream = new MemoryStream(); TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); InventoryItemBase item1 = new InventoryItemBase(); item1.Name = itemName; item1.AssetID = UUID.Random(); item1.GroupID = UUID.Random(); item1.CreatorId = OspResolver.MakeOspa(user2FirstName, user2LastName); item1.Owner = UUID.Zero; string item1FileName = string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, archiveItemName); tar.WriteFile(item1FileName, UserInventoryItemSerializer.Serialize(item1)); tar.Close(); MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); SerialiserModule serialiserModule = new SerialiserModule(); InventoryArchiverModule archiverModule = new InventoryArchiverModule(); // Annoyingly, we have to set up a scene even though inventory loading has nothing to do with a scene Scene scene = SceneSetupHelpers.SetupScene(); IUserAdminService userAdminService = scene.CommsManager.UserAdminService; SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); userAdminService.AddUser( userFirstName, userLastName, "meowfood", String.Empty, 1000, 1000, userUuid); archiverModule.DearchiveInventory(userFirstName, userLastName, "/", archiveReadStream); // Check that a suitable temporary user profile has been created. UserProfileData user2Profile = scene.CommsManager.UserService.GetUserProfile( OspResolver.HashName(user2FirstName + " " + user2LastName)); Assert.That(user2Profile, Is.Not.Null); Assert.That(user2Profile.FirstName == user2FirstName); Assert.That(user2Profile.SurName == user2LastName); CachedUserInfo userInfo = scene.CommsManager.UserProfileCacheService.GetUserDetails(userFirstName, userLastName); userInfo.FetchInventory(); for (int i = 0; i < 50; i++) { if (userInfo.HasReceivedInventory == true) { break; } Thread.Sleep(200); } Assert.That(userInfo.HasReceivedInventory, Is.True, "FetchInventory timed out (10 seconds)"); InventoryItemBase foundItem = userInfo.RootFolder.FindItemByPath(itemName); Assert.That(foundItem.CreatorId, Is.EqualTo(item1.CreatorId)); Assert.That( foundItem.CreatorIdAsUuid, Is.EqualTo(OspResolver.HashName(user2FirstName + " " + user2LastName))); Assert.That(foundItem.Owner, Is.EqualTo(userUuid)); Console.WriteLine("### Successfully completed {0} ###", MethodBase.GetCurrentMethod()); }