improve relay and datastore

datastore can now prefetch display names (note the first time it sees a avatar the display name will be ?)
the relay service can now talk to rabbit as a target
the relay service can now use an extended output json
This commit is contained in:
Madpeter 2025-07-10 00:27:55 +01:00
parent 68d1cd08e0
commit 851328c74e
5 changed files with 165 additions and 22 deletions

View file

@ -42,6 +42,7 @@ ENV basic_Username='' \
datastore_AutoCleanAvatars='true' \ datastore_AutoCleanAvatars='true' \
datastore_AvatarsCleanAfterMins=10 \ datastore_AvatarsCleanAfterMins=10 \
datastore_LocalChatHistoryLimit=120 \ datastore_LocalChatHistoryLimit=120 \
datastore_PrefetchAvatarDisplaynames='true' \
datastore_GroupChatHistoryLimitPerGroup=50 \ datastore_GroupChatHistoryLimitPerGroup=50 \
datastore_ImChatHistoryLimit=50 \ datastore_ImChatHistoryLimit=50 \
datastore_PrefetchGroupMembers='true' \ datastore_PrefetchGroupMembers='true' \

View file

@ -17,12 +17,17 @@ namespace SecondBotEvents.Config
settings.Add("PrefetchGroupMembers"); settings.Add("PrefetchGroupMembers");
settings.Add("PrefetchGroupRoles"); settings.Add("PrefetchGroupRoles");
settings.Add("PrefetchEstateBanlist"); settings.Add("PrefetchEstateBanlist");
settings.Add("PrefetchAvatarDisplaynames");
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 bool GetPrefetchAvatarDisplaynames()
{
return ReadSettingAsBool("PrefetchAvatarDisplaynames", true);
}
public int GetCommandHistoryLimit() public int GetCommandHistoryLimit()
{ {

View file

@ -34,6 +34,15 @@ namespace SecondBotEvents.Config
return true; return true;
} }
public bool GetRelayJson(int relayID)
{
if (GetUseShortEncoder() == false)
{
return ReadSettingAsBool(relayID.ToString() + "_extended", false);
}
return true;
}
public string RelaySourceType(int relayID) public string RelaySourceType(int relayID)
{ {
if (GetUseShortEncoder() == false) if (GetUseShortEncoder() == false)

View file

@ -9,6 +9,7 @@ using System.Threading;
using SecondBotEvents.Commands; using SecondBotEvents.Commands;
using OpenMetaverse.ImportExport.Collada14; using OpenMetaverse.ImportExport.Collada14;
using System.Threading.Tasks; using System.Threading.Tasks;
using OpenMetaverse.Messages.Linden;
namespace SecondBotEvents.Services namespace SecondBotEvents.Services
{ {
@ -23,6 +24,7 @@ namespace SecondBotEvents.Services
protected Dictionary<string, UUID> avatarsName2Key = []; protected Dictionary<string, UUID> avatarsName2Key = [];
protected Dictionary<UUID, long> avatarLastUsed = []; protected Dictionary<UUID, long> avatarLastUsed = [];
protected Dictionary<UUID, string> avatarsKey2Displayname = [];
protected Dictionary<UUID, string> groupsKey2Name = []; protected Dictionary<UUID, string> groupsKey2Name = [];
@ -195,12 +197,13 @@ namespace SecondBotEvents.Services
} }
clearLinks.Add(entry.Value, entry.Key); clearLinks.Add(entry.Value, entry.Key);
} }
lock (avatarLastUsed) lock(avatarsName2Key) lock (avatarLastUsed) lock (avatarsName2Key) lock(avatarsKey2Displayname)
{ {
foreach (KeyValuePair<UUID, string> A in clearLinks) foreach (KeyValuePair<UUID, string> A in clearLinks)
{ {
avatarLastUsed.Remove(A.Key); avatarLastUsed.Remove(A.Key);
avatarsName2Key.Remove(A.Value); avatarsName2Key.Remove(A.Value);
avatarsKey2Displayname.Remove(A.Key);
} }
} }
} }
@ -1025,6 +1028,11 @@ namespace SecondBotEvents.Services
} }
lock (localChatHistory) lock (localChatHistory)
{ {
if (source == "{Av}")
{
AddAvatar(e.SourceID, e.FromName);
}
localChatHistory.Add(source+ " "+e.FromName + ": " + e.Message); localChatHistory.Add(source+ " "+e.FromName + ": " + e.Message);
if (localChatHistory.Count <= myConfig.GetLocalChatHistoryLimit()) if (localChatHistory.Count <= myConfig.GetLocalChatHistoryLimit())
{ {
@ -1087,18 +1095,53 @@ namespace SecondBotEvents.Services
GetClient().Groups.RequestCurrentGroups(); GetClient().Groups.RequestCurrentGroups();
} }
protected void displayNameFinder(UUID Avatar)
{
if (myConfig.GetPrefetchAvatarDisplaynames() == true)
{
requestDisplayName(Avatar);
}
}
protected void requestDisplayName(UUID Avatar)
{
if (avatarsKey2Displayname.ContainsKey(Avatar) == false)
{
return; // unable to fetch not in avatar DB
}
if (avatarsKey2Displayname[Avatar] != "?")
{
return; // already known
}
_ = GetClient().Avatars.RequestAgentProfile(Avatar, (status, properties) =>
{
avatarsKey2Displayname[Avatar] = properties.DisplayName;
});
}
public void AddAvatar(UUID id, string name) public void AddAvatar(UUID id, string name)
{ {
lock (avatarsName2Key) lock (avatarLastUsed) lock (avatarsName2Key) lock (avatarLastUsed) lock(avatarsKey2Displayname)
{
if (avatarsName2Key.ContainsValue(id) == true)
{ {
avatarLastUsed[id] = SecondbotHelpers.UnixTimeNow(); if (avatarsName2Key.ContainsValue(id) == true)
return; {
avatarLastUsed[id] = SecondbotHelpers.UnixTimeNow();
displayNameFinder(id);
return;
}
avatarsName2Key.Add(name, id);
avatarLastUsed.Add(id, SecondbotHelpers.UnixTimeNow());
avatarsKey2Displayname.Add(id, "?");
displayNameFinder(id);
} }
avatarsName2Key.Add(name, id); }
avatarLastUsed.Add(id, SecondbotHelpers.UnixTimeNow());
public string GetDisplayName(UUID id)
{
requestDisplayName(id);
if (avatarsKey2Displayname.ContainsKey(id) == false)
{
return "?";
} }
return avatarsKey2Displayname[id];
} }
protected void AvatarUUIDName(object o, UUIDNameReplyEventArgs e) protected void AvatarUUIDName(object o, UUIDNameReplyEventArgs e)

View file

@ -71,7 +71,15 @@ namespace SecondBotEvents.Services
protected void DiscordMessage(object o, SocketMessage e) protected void DiscordMessage(object o, SocketMessage e)
{ {
triggerRelayEvent("discord", e.Source.ToString(), e.Channel.ToString(), e.Author.Username, e.CleanContent); triggerRelayEvent(
"discord",
e.Source.ToString(),
e.Channel.ToString(),
e.Author.Username,
e.CleanContent,
e.Channel.Name,
e.Author.GlobalName
);
} }
readonly string[] hard_blocked_agents = ["secondlife", "second life"]; readonly string[] hard_blocked_agents = ["secondlife", "second life"];
@ -91,6 +99,7 @@ namespace SecondBotEvents.Services
break; break;
} }
string source = "avatar"; string source = "avatar";
string sourcename = e.Type.ToString().ToLowerInvariant();
if (e.SourceType == ChatSourceType.Object) if (e.SourceType == ChatSourceType.Object)
{ {
source = "object"; source = "object";
@ -103,8 +112,21 @@ namespace SecondBotEvents.Services
{ {
source = "ownersay"; source = "ownersay";
} }
string triggerdisplayname = e.SourceID.ToString();
if (source == "avatar")
{
triggerdisplayname = master.DataStoreService.GetDisplayName(e.SourceID);
}
// trigger localchat // trigger localchat
triggerRelayEvent("localchat", source, e.SourceID.ToString(), e.FromName, e.Message); triggerRelayEvent(
source: "localchat",
filter: source,
sourceuuid: e.SourceID.ToString(),
triggername: e.FromName,
message: e.Message,
sourcename: sourcename,
triggerdisplayname: triggerdisplayname
);
break; break;
} }
default: default:
@ -121,7 +143,15 @@ namespace SecondBotEvents.Services
case InstantMessageDialog.MessageFromObject: case InstantMessageDialog.MessageFromObject:
{ {
// trigger object IM // trigger object IM
triggerRelayEvent("object", e.IM.FromAgentID.ToString(), e.IM.IMSessionID.ToString(), e.IM.FromAgentName, e.IM.Message); triggerRelayEvent(
source: "object",
filter: e.IM.FromAgentID.ToString(),
sourceuuid: e.IM.IMSessionID.ToString(),
triggername: e.IM.FromAgentName,
message: e.IM.Message,
sourcename: e.IM.Dialog.ToString(),
triggerdisplayname: "objectim"
);
break; break;
} }
case InstantMessageDialog.MessageFromAgent: // shared with SessionSend case InstantMessageDialog.MessageFromAgent: // shared with SessionSend
@ -130,8 +160,15 @@ namespace SecondBotEvents.Services
if (master.DataStoreService.GetIsGroup(e.IM.IMSessionID) == false) if (master.DataStoreService.GetIsGroup(e.IM.IMSessionID) == false)
{ {
// trigger avatar IM // trigger avatar IM
triggerRelayEvent("avatar", e.IM.FromAgentID.ToString(), e.IM.IMSessionID.ToString(), e.IM.FromAgentName, e.IM.Message); triggerRelayEvent(
break; source: "avatar",
filter: e.IM.FromAgentID.ToString(),
sourceuuid: e.IM.IMSessionID.ToString(),
triggername: e.IM.FromAgentName,
message: e.IM.Message,
sourcename: e.IM.Dialog.ToString(),
triggerdisplayname: master.DataStoreService.GetDisplayName(e.IM.FromAgentID)
);
} }
// trigger group IM // trigger group IM
string groupname = "?"; string groupname = "?";
@ -139,7 +176,15 @@ namespace SecondBotEvents.Services
{ {
groupname = GetClient().Groups.GroupName2KeyCache[e.IM.IMSessionID]; groupname = GetClient().Groups.GroupName2KeyCache[e.IM.IMSessionID];
} }
triggerRelayEvent("group", groupname, e.IM.IMSessionID.ToString(), e.IM.FromAgentName, e.IM.Message); triggerRelayEvent(
source: "group",
filter: groupname,
sourceuuid: e.IM.IMSessionID.ToString(),
triggername: e.IM.FromAgentName,
message: e.IM.Message,
sourcename: e.IM.Dialog.ToString(),
triggerdisplayname: master.DataStoreService.GetDisplayName(e.IM.FromAgentID)
);
break; break;
} }
default: default:
@ -149,7 +194,16 @@ namespace SecondBotEvents.Services
} }
} }
protected void triggerRelayEvent(string source, string filter, string sourceuuid, string name, string message) protected void triggerRelayEvent(
string source,
string filter,
string sourceuuid,
string triggername,
string message,
string sourcename="",
string triggerdisplayname=""
)
{ {
int loop = 1; int loop = 1;
if(message.Contains("{Relay}") == true) if(message.Contains("{Relay}") == true)
@ -160,11 +214,24 @@ namespace SecondBotEvents.Services
relayEvent a = new() relayEvent a = new()
{ {
message = message, message = message,
name = name, name = triggername,
sourcetype = source, sourcetype = source,
sourceoption = filter sourceoption = filter
}; };
string eventMessage = JsonConvert.SerializeObject(a); string eventMessage = JsonConvert.SerializeObject(a);
relayEventExtended relayEventExtended = new()
{
source = source,
sourceid = filter,
sourcename = sourcename,
triggerid = sourceuuid,
triggername = triggername,
triggerdisplayname = triggerdisplayname,
message = message,
unixtime = SecondbotHelpers.UnixTimeNow().ToString()
};
string eventMessageExtended = JsonConvert.SerializeObject(relayEventExtended);
while (loop <= myConfig.GetRelayCount()) while (loop <= myConfig.GetRelayCount())
{ {
int index = loop; int index = loop;
@ -183,7 +250,8 @@ namespace SecondBotEvents.Services
} }
string targetType = myConfig.RelayTargetType(index); string targetType = myConfig.RelayTargetType(index);
string targetOption = myConfig.RelayTargetOption(index); string targetOption = myConfig.RelayTargetOption(index);
if(targetType == "localchat") string useEventMessage = myConfig.GetRelayJson(index) ? eventMessageExtended : eventMessage;
if (targetType == "localchat")
{ {
if(int.TryParse(targetOption, out int target) == false) if(int.TryParse(targetOption, out int target) == false)
{ {
@ -193,7 +261,7 @@ namespace SecondBotEvents.Services
{ {
continue; continue;
} }
GetClient().Self.Chat(eventMessage, target, ChatType.Normal); GetClient().Self.Chat(useEventMessage, target, ChatType.Normal);
} }
else if(targetType == "group") else if(targetType == "group")
{ {
@ -201,7 +269,7 @@ namespace SecondBotEvents.Services
{ {
continue; continue;
} }
GetClient().Self.InstantMessageGroup(targetuuid, eventMessage); GetClient().Self.InstantMessageGroup(targetuuid, useEventMessage);
} }
else if(targetType == "avatar") else if(targetType == "avatar")
{ {
@ -209,7 +277,7 @@ namespace SecondBotEvents.Services
{ {
continue; continue;
} }
GetClient().Self.InstantMessage(targetuuid, eventMessage); GetClient().Self.InstantMessage(targetuuid, useEventMessage);
} }
else if(targetType == "http") else if(targetType == "http")
{ {
@ -222,7 +290,7 @@ namespace SecondBotEvents.Services
request.AddParameter("method", "Relay"); request.AddParameter("method", "Relay");
request.AddParameter("action", "Service"); request.AddParameter("action", "Service");
request.AddParameter("botname", GetClient().Self.Name); request.AddParameter("botname", GetClient().Self.Name);
request.AddParameter("event", eventMessage); request.AddParameter("event", useEventMessage);
request.AddHeader("content-type", "application/x-www-form-urlencoded"); request.AddHeader("content-type", "application/x-www-form-urlencoded");
client.ExecutePostAsync(request); client.ExecutePostAsync(request);
} }
@ -245,7 +313,11 @@ namespace SecondBotEvents.Services
{ {
continue; continue;
} }
master.DiscordService.SendMessageToChannel(targetserver, targetchannel, message); master.DiscordService.SendMessageToChannel(targetserver, targetchannel, useEventMessage);
}
else if(targetType == "rabbit")
{
master.RabbitService.SendMessage(targetOption, useEventMessage);
} }
} }
} }
@ -282,5 +354,18 @@ namespace SecondBotEvents.Services
public string sourcetype = ""; public string sourcetype = "";
public string sourceoption = ""; public string sourceoption = "";
} }
public class relayEventExtended
{
public string source = "";
public string sourceid = "";
public string sourcename = "";
public string triggerid = "";
public string triggername = "";
public string triggerdisplayname = "";
public string message = "";
public string unixtime = "";
}
} }