SecondBot/SecondBotEvents/Services/RelayService.cs
Madpeter 851328c74e 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
2025-07-10 00:27:55 +01:00

371 lines
14 KiB
C#

using Newtonsoft.Json;
using OpenMetaverse;
using SecondBotEvents.Config;
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Net.Http;
using OpenMetaverse.ImportExport.Collada14;
using System.Configuration;
using RestSharp;
using System.Security.Policy;
using Discord.WebSocket;
namespace SecondBotEvents.Services
{
public class RelayService : BotServices
{
protected new RelayConfig myConfig;
protected bool botConnected = false;
public RelayService(EventsSecondBot setMaster) : base(setMaster)
{
myConfig = new RelayConfig(master.fromEnv, master.fromFolder);
}
public override string Status()
{
if (myConfig == null)
{
return "No Config";
}
else if (myConfig.GetHideStatusOutput() == true)
{
return "hidden";
}
else if (botConnected == false)
{
return "Waiting for bot";
}
return "Active";
}
protected void BotClientRestart(object o, BotClientNotice e)
{
if (e.isStart == false)
{
return;
}
botConnected = false;
LogFormater.Info("Relay Service [Attached to new client]");
GetClient().Network.LoggedOut += BotLoggedOut;
GetClient().Network.SimConnected += BotLoggedIn;
}
protected void BotLoggedOut(object o, LoggedOutEventArgs e)
{
botConnected = false;
GetClient().Network.SimConnected += BotLoggedIn;
LogFormater.Info("Relay Service [Standby]");
}
protected void BotLoggedIn(object o, SimConnectedEventArgs e)
{
GetClient().Network.SimConnected -= BotLoggedIn;
GetClient().Self.IM += BotImMessage;
GetClient().Self.ChatFromSimulator += LocalChat;
master.DiscordService.DiscordMessageEvent += DiscordMessage;
botConnected = true;
LogFormater.Info("Relay Service [Active]");
}
protected void DiscordMessage(object o, SocketMessage e)
{
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"];
protected void LocalChat(object o, ChatEventArgs e)
{
switch (e.Type)
{
case ChatType.OwnerSay:
case ChatType.Whisper:
case ChatType.Normal:
case ChatType.Shout:
case ChatType.RegionSayTo:
{
if (hard_blocked_agents.Contains(e.FromName.ToLowerInvariant()) == true)
{
break;
}
string source = "avatar";
string sourcename = e.Type.ToString().ToLowerInvariant();
if (e.SourceType == ChatSourceType.Object)
{
source = "object";
}
else if (e.SourceType == ChatSourceType.System)
{
source = "system";
}
if (e.Type == ChatType.OwnerSay)
{
source = "ownersay";
}
string triggerdisplayname = e.SourceID.ToString();
if (source == "avatar")
{
triggerdisplayname = master.DataStoreService.GetDisplayName(e.SourceID);
}
// trigger localchat
triggerRelayEvent(
source: "localchat",
filter: source,
sourceuuid: e.SourceID.ToString(),
triggername: e.FromName,
message: e.Message,
sourcename: sourcename,
triggerdisplayname: triggerdisplayname
);
break;
}
default:
{
break;
}
}
}
protected void BotImMessage(object o, InstantMessageEventArgs e)
{
switch (e.IM.Dialog)
{
case InstantMessageDialog.MessageFromObject:
{
// trigger object IM
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;
}
case InstantMessageDialog.MessageFromAgent: // shared with SessionSend
case InstantMessageDialog.SessionSend:
{
if (master.DataStoreService.GetIsGroup(e.IM.IMSessionID) == false)
{
// trigger avatar IM
triggerRelayEvent(
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
string groupname = "?";
if(GetClient().Groups.GroupName2KeyCache.ContainsKey(e.IM.IMSessionID) == true)
{
groupname = GetClient().Groups.GroupName2KeyCache[e.IM.IMSessionID];
}
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;
}
default:
{
break;
}
}
}
protected void triggerRelayEvent(
string source,
string filter,
string sourceuuid,
string triggername,
string message,
string sourcename="",
string triggerdisplayname=""
)
{
int loop = 1;
if(message.Contains("{Relay}") == true)
{
return;
}
message = "{Relay} " + message;
relayEvent a = new()
{
message = message,
name = triggername,
sourcetype = source,
sourceoption = filter
};
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())
{
int index = loop;
loop++;
if (myConfig.GetRelayEnabled(index) != true)
{
continue;
}
if(myConfig.RelaySourceType(index) != source)
{
continue;
}
if ((myConfig.RelaySourceOption(index) != filter) && (myConfig.RelaySourceOption(index) != sourceuuid))
{
continue;
}
string targetType = myConfig.RelayTargetType(index);
string targetOption = myConfig.RelayTargetOption(index);
string useEventMessage = myConfig.GetRelayJson(index) ? eventMessageExtended : eventMessage;
if (targetType == "localchat")
{
if(int.TryParse(targetOption, out int target) == false)
{
continue;
}
if(target < 0)
{
continue;
}
GetClient().Self.Chat(useEventMessage, target, ChatType.Normal);
}
else if(targetType == "group")
{
if (UUID.TryParse(targetOption, out UUID targetuuid) == false)
{
continue;
}
GetClient().Self.InstantMessageGroup(targetuuid, useEventMessage);
}
else if(targetType == "avatar")
{
if (UUID.TryParse(targetOption, out UUID targetuuid) == false)
{
continue;
}
GetClient().Self.InstantMessage(targetuuid, useEventMessage);
}
else if(targetType == "http")
{
long unixtime = SecondbotHelpers.UnixTimeNow();
string token = SecondbotHelpers.GetSHA1(unixtime.ToString() + "RelayService" + GetClient().Self.AgentID + eventMessage + master.CommandsService.myConfig.GetSharedSecret());
var client = new RestClient(targetOption);
var request = new RestRequest("Relay/Service", Method.Post);
request.AddParameter("token", token);
request.AddParameter("unixtime", unixtime.ToString());
request.AddParameter("method", "Relay");
request.AddParameter("action", "Service");
request.AddParameter("botname", GetClient().Self.Name);
request.AddParameter("event", useEventMessage);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
client.ExecutePostAsync(request);
}
else if(targetType == "discord")
{
if(master.DiscordService.isRunning() == false)
{
continue;
}
string[] bits = targetOption.Split('|');
if(bits.Length != 2 )
{
continue;
}
if (ulong.TryParse(bits[0],out ulong targetserver) == false)
{
continue;
}
if (ulong.TryParse(bits[1], out ulong targetchannel) == false)
{
continue;
}
master.DiscordService.SendMessageToChannel(targetserver, targetchannel, useEventMessage);
}
else if(targetType == "rabbit")
{
master.RabbitService.SendMessage(targetOption, useEventMessage);
}
}
}
public override void Start(bool updateEnabled = false, bool setEnabledTo = false)
{
if (updateEnabled)
{
myConfig.setEnabled(setEnabledTo);
}
Stop();
running = true;
master.BotClientNoticeEvent += BotClientRestart;
LogFormater.Info("Relay Service [Starting]");
}
public override void Stop()
{
if(running == true)
{
LogFormater.Info("Relay Service [Stopping]");
}
running = false;
master.BotClientNoticeEvent -= BotClientRestart;
}
}
public class relayEvent
{
public string name = "";
public string message = "";
public string sourcetype = "";
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 = "";
}
}