Add inventory prefetching support

Introduces configuration options and logic for prefetching inventory folders on startup, including depth control. Updates Dockerfile and DataStoreConfig to support new settings, and modifies DataStoreService to handle inventory preloading asynchronously.
This commit is contained in:
Madpeter 2025-10-02 11:22:19 +01:00
parent c40c551316
commit c00a11a99d
4 changed files with 75 additions and 5 deletions

View file

@ -47,6 +47,8 @@ ENV basic_Username='' \
datastore_ImChatHistoryLimit=50 \ datastore_ImChatHistoryLimit=50 \
datastore_PrefetchGroupMembers='true' \ datastore_PrefetchGroupMembers='true' \
datastore_PrefetchGroupRoles='false' \ datastore_PrefetchGroupRoles='false' \
datastore_PrefetchInventory='false' \
datastore_PrefetchInventoryDepth='2' \
datastore_PrefetchEstateBanlist='true' \ datastore_PrefetchEstateBanlist='true' \
datastore_AutoCleanKeyValueStore='true' \ datastore_AutoCleanKeyValueStore='true' \
datastore_CleanKeyValueStoreAfterMins=10 \ datastore_CleanKeyValueStoreAfterMins=10 \

View file

@ -18,11 +18,21 @@ namespace SecondBotEvents.Config
settings.Add("PrefetchGroupRoles"); settings.Add("PrefetchGroupRoles");
settings.Add("PrefetchEstateBanlist"); settings.Add("PrefetchEstateBanlist");
settings.Add("PrefetchAvatarDisplaynames"); settings.Add("PrefetchAvatarDisplaynames");
settings.Add("PrefetchInventory");
settings.Add("PrefetchInventoryDepth");
settings.Add("AutoCleanKeyValueStore"); settings.Add("AutoCleanKeyValueStore");
settings.Add("CleanKeyValueStoreAfterMins"); settings.Add("CleanKeyValueStoreAfterMins");
settings.Add("CommandHistoryLimit"); settings.Add("CommandHistoryLimit");
settings.Add("HideStatusOutput"); settings.Add("HideStatusOutput");
} }
public int GetPrefetchInventoryDepth()
{
return ReadSettingAsInt("PrefetchInventoryDepth", 2);
}
public bool GetPrefetchInventory()
{
return ReadSettingAsBool("PrefetchInventory", false);
}
public bool GetPrefetchAvatarDisplaynames() public bool GetPrefetchAvatarDisplaynames()
{ {

View file

@ -436,14 +436,15 @@ namespace SecondBotEvents.Services
public void CommandNotice(string command,string source, string args,bool accepted, string results) public void CommandNotice(string command,string source, string args,bool accepted, string results)
{ {
if(myConfig.GetCommandHistoryLogResults() == false)
{
results = "";
}
BotCommandNotice e = new(command, args, source, accepted, results); BotCommandNotice e = new(command, args, source, accepted, results);
EventHandler<BotCommandNotice> handler = BotclientCommandEventNotices; EventHandler<BotCommandNotice> handler = BotclientCommandEventNotices;
handler?.Invoke(this, e); handler?.Invoke(this, e);
if(master.BotClient.basicCfg.GetLogCommands() == true) if (myConfig.GetCommandHistoryLogResults() == false)
{
return;
}
if (master.BotClient.basicCfg.GetLogCommands() == true)
{ {
LogFormater.Info("Command log:" + JsonConvert.SerializeObject(e)); LogFormater.Info("Command log:" + JsonConvert.SerializeObject(e));
} }

View file

@ -10,6 +10,8 @@ using SecondBotEvents.Commands;
using OpenMetaverse.ImportExport.Collada14; using OpenMetaverse.ImportExport.Collada14;
using System.Threading.Tasks; using System.Threading.Tasks;
using OpenMetaverse.Messages.Linden; using OpenMetaverse.Messages.Linden;
using Org.BouncyCastle.Asn1.BC;
using Swan;
namespace SecondBotEvents.Services namespace SecondBotEvents.Services
{ {
@ -208,6 +210,17 @@ namespace SecondBotEvents.Services
} }
} }
} }
if (myConfig.GetPrefetchInventory() == true)
{
if(preloadDone == false)
{
if(preloadingFolders.Count() == 0)
{
preloadDone = true;
}
return "Loading "+preloadingFolders.Count()+" inventory folders";
}
}
int sum = commandHistories.Count + KeyValueStoreLastUsed.Count + KeyValueStore.Count + int sum = commandHistories.Count + KeyValueStoreLastUsed.Count + KeyValueStore.Count +
chatWindowsOwner.Count + chatWindowsIsGroup.Count + chatWindowsUnread.Count + chatWindowsOwner.Count + chatWindowsIsGroup.Count + chatWindowsUnread.Count +
chatWindows.Count + localChatHistory.Count + groupRoles.Count + chatWindows.Count + localChatHistory.Count + groupRoles.Count +
@ -999,7 +1012,51 @@ namespace SecondBotEvents.Services
GetClient().Avatars.AvatarPropertiesReply += AvatarDetailsReply; GetClient().Avatars.AvatarPropertiesReply += AvatarDetailsReply;
GetClient().Groups.RequestCurrentGroups(); GetClient().Groups.RequestCurrentGroups();
_ = GetClient().Self.RetrieveInstantMessages(); _ = GetClient().Self.RetrieveInstantMessages();
if(myConfig.GetPrefetchInventory() == true)
{
preloadDone = false;
Task.Run(() =>
{
preloadFolder("root", GetClient().Inventory.Store.RootFolder.UUID, myConfig.GetPrefetchInventoryDepth(), 0);
});
}
} }
protected List<string> preloadingFolders = [];
protected bool preloadDone = true;
protected async void preloadFolder(string foldername,UUID folder, int maxDepth, int currentDepth)
{
await Task.Run(async () =>
{
lock (preloadingFolders)
{
preloadingFolders.Add(folder.Guid.ToString());
}
await Task.Delay(1000 * currentDepth);
List<InventoryBase> foldercontents = GetClient().Inventory.FolderContents(
GetClient().Inventory.Store.RootFolder.UUID,
GetClient().Self.AgentID, true, true,
InventorySortOrder.ByName, TimeSpan.FromSeconds(30), false);
foreach (InventoryBase item in foldercontents)
{
if (item is InventoryFolder == false)
{
continue;
}
if ((currentDepth + 1) > maxDepth)
{
continue;
}
preloadFolder(item.Name, item.UUID, maxDepth, currentDepth + 1);
}
lock (preloadingFolders)
{
preloadingFolders.Remove(folder.Guid.ToString());
}
});
}
readonly string[] hard_blocked_agents = ["secondlife", "second life"]; readonly string[] hard_blocked_agents = ["secondlife", "second life"];
protected void ChatFromSim(object o, ChatEventArgs e) protected void ChatFromSim(object o, ChatEventArgs e)
{ {