From ed64a509bf9571dd2d1607a2c91d30013fbcc670 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Thu, 22 Sep 2022 01:59:37 +0100 Subject: [PATCH] dialog relay support --- SecondBotEvents/Commands/Dialogs.cs | 87 ++++--- SecondBotEvents/Config/DialogRelayConfig.cs | 40 ++++ SecondBotEvents/EventsSecondBot.cs | 2 + SecondBotEvents/Services/DialogService.cs | 239 ++++++++++++++++++++ 4 files changed, 342 insertions(+), 26 deletions(-) create mode 100644 SecondBotEvents/Config/DialogRelayConfig.cs create mode 100644 SecondBotEvents/Services/DialogService.cs diff --git a/SecondBotEvents/Commands/Dialogs.cs b/SecondBotEvents/Commands/Dialogs.cs index a7ef234..352f35d 100644 --- a/SecondBotEvents/Commands/Dialogs.cs +++ b/SecondBotEvents/Commands/Dialogs.cs @@ -1,4 +1,5 @@ -using SecondBotEvents.Services; +using OpenMetaverse; +using SecondBotEvents.Services; namespace SecondBotEvents.Commands @@ -8,21 +9,68 @@ namespace SecondBotEvents.Commands public Dialogs(EventsSecondBot setmaster) : base(setmaster) { } - [About("Updates the relay target (you can have 1 of each type)
Clear will disable them all")] - [ReturnHints("cleared")] - [ReturnHints("set/avatar [ok]")] - [ReturnHints("set/http [ok]")] - [ReturnHints("set/channel [ok]")] - [ReturnHintsFailure("Not a vaild option")] - [ArgHints("target", "Options: Channel (Any number),Avatar UUID,HTTPurl
Clear")] - public object DialogRelay(string target) + + [About("adds a avatar dialog relay target [or removes if it exists]")] + [ReturnHints("added")] + [ReturnHints("removed")] + [ReturnHintsFailure("unable to find avatar")] + [ReturnHintsFailure("looking up avatar please try again")] + [ArgHints("avatar", "the UUID or avatar name to add")] + public object DialogRelayAvatarTarget(string avatar) { - return Failure("@todo dialog relay"); + if(UUID.TryParse(avatar, out UUID avUUID) == false) + { + string avataruuid = master.DataStoreService.GetAvatarUUID(avatar); + if (avataruuid == "lookup") + { + return Failure("looking up avatar please try again"); + } + if (UUID.TryParse(avataruuid, out avUUID) == false) + { + return Failure("unable to find avatar"); + } + } + return BasicReply(master.DialogService.AvatarRelayTarget(avUUID)); } + [About("adds a chat dialog relay target [or removes if it exists]")] + [ReturnHints("added")] + [ReturnHints("removed")] + [ReturnHintsFailure("channel must be zero or more")] + [ReturnHintsFailure("channel is not vaild")] + [ArgHints("channel", "a number >= 0")] + public object DialogRelayChatTarget(string channel) + { + if (int.TryParse(channel, out int channelnum) == false) + { + return Failure("channel is not vaild"); + } + if(channelnum < 0) + { + return Failure("channel must be zero or more"); + } + return BasicReply(master.DialogService.ChannelRelayTarget(channelnum)); + } + + [About("adds a http dialog relay target [or removes if it exists]")] + [ReturnHints("added")] + [ReturnHints("removed")] + [ReturnHintsFailure("url must start with http")] + [ArgHints("url", "a vaild http url")] + public object DialogRelayHttpTarget(string url) + { + if(url.StartsWith("http") == false) + { + return Failure("url must start with http"); + } + return BasicReply(master.DialogService.HttpRelayTarget(url)); + } + + [About("Makes the bot interact with the dialog [dialogid] with the button [buttontext]")] - [ReturnHints("true")] - [ReturnHints("false")] + [ReturnHints("action")] + [ReturnHintsFailure("Invaild dialog window")] + [ReturnHintsFailure("Invaild dialog button")] [ReturnHintsFailure("bad dialog id")] [ArgHints("dialogid", "The ID for the dialog")] [ArgHints("buttontext", "The button text to push")] @@ -32,20 +80,7 @@ namespace SecondBotEvents.Commands { return Failure("bad dialog id", new [] { dialogid, buttontext }); } - return Failure("@todo dialog relay"); - } - - [About("Should the bot track dialogs and send them to the relays setup?")] - [ReturnHints("updated")] - [ReturnHintsFailure("bad status")] - [ArgHints("status", "true or false")] - public object DialogTrack(string status) - { - if (bool.TryParse(status, out bool statuscode) == false) - { - return Failure("bad status", new [] { status }); - } - return Failure("@todo dialog relay"); + return BasicReply(master.DialogService.DialogAction(dialogidnum, buttontext)); } } diff --git a/SecondBotEvents/Config/DialogRelayConfig.cs b/SecondBotEvents/Config/DialogRelayConfig.cs new file mode 100644 index 0000000..07daafb --- /dev/null +++ b/SecondBotEvents/Config/DialogRelayConfig.cs @@ -0,0 +1,40 @@ +using OpenMetaverse; +using System; +using System.Collections.Generic; +using System.Text; + +namespace SecondBotEvents.Config +{ + public class DialogRelayConfig : Config + { + public DialogRelayConfig(bool fromENV, string fromFolder = "") : base(fromENV, fromFolder) { } + protected override void MakeSettings() + { + filename = "dialogrelay"; + settings.Add("RelayChannel"); + settings.Add("RelayAvatar"); + settings.Add("RelayObjectOwnerOnly"); + settings.Add("RelayHttpurl"); + } + + public string GetRelayHttpurl() + { + return ReadSettingAsString("RelayHttpurl", "-"); + } + + public int GetRelayChannel() + { + return ReadSettingAsInt("RelayChannel", -1); + } + + public string GetRelayAvatar() + { + return ReadSettingAsString("RelayAvatar", UUID.Zero.ToString()); + } + + public string RelayObjectOwnerOnly() + { + return ReadSettingAsString("RelayObjectOwnerOnly", UUID.Zero.ToString()); + } + } +} \ No newline at end of file diff --git a/SecondBotEvents/EventsSecondBot.cs b/SecondBotEvents/EventsSecondBot.cs index de81870..7188606 100644 --- a/SecondBotEvents/EventsSecondBot.cs +++ b/SecondBotEvents/EventsSecondBot.cs @@ -37,6 +37,7 @@ namespace SecondBotEvents public DataStoreService DataStoreService { get { return (DataStoreService)GetService("DataStoreService"); } } public HomeboundService HomeboundService { get { return (HomeboundService)GetService("HomeboundService"); } } public EventsService EventsService { get { return (EventsService)GetService("EventsService"); } } + public DialogService DialogService { get { return (DialogService)GetService("DialogService"); } } private EventHandler SystemStatusMessages; @@ -147,6 +148,7 @@ namespace SecondBotEvents RegisterService("InteractionService"); RegisterService("HomeboundService"); RegisterService("EventsService"); + RegisterService("DialogService"); if (BotClient.IsLoaded() == false) { Console.WriteLine("Config is not loaded :("); diff --git a/SecondBotEvents/Services/DialogService.cs b/SecondBotEvents/Services/DialogService.cs new file mode 100644 index 0000000..66f2e26 --- /dev/null +++ b/SecondBotEvents/Services/DialogService.cs @@ -0,0 +1,239 @@ +using OpenMetaverse; +using SecondBotEvents.Config; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using Newtonsoft.Json; +using System.Linq; +using Swan; +using SecondBotEvents.Commands; + +namespace SecondBotEvents.Services +{ + public class DialogService : BotServices + { + protected bool botConnected = false; + protected DialogRelayConfig myConfig; + public DialogService(EventsSecondBot setMaster) : base(setMaster) + { + myConfig = new DialogRelayConfig(master.fromEnv, master.fromFolder); + if(myConfig.GetRelayChannel() >= 0) + { + DialogRelayChannels.Add(myConfig.GetRelayChannel()); + } + if(UUID.TryParse(myConfig.GetRelayAvatar(), out UUID newAV) == true) + { + if(newAV != UUID.Zero) + { + DialogRelayAvatars.Add(newAV); + } + } + if (UUID.TryParse(myConfig.RelayObjectOwnerOnly(), out UUID newObjectOwnerAv) == true) + { + if (newObjectOwnerAv != UUID.Zero) + { + objectOwnerOnly = newObjectOwnerAv; + } + } + if(myConfig.GetRelayHttpurl().StartsWith("http") == true) + { + DialogRelayHTTP.Add(myConfig.GetRelayHttpurl()); + } + } + public override string Status() + { + if(botConnected == false) + { + return "Waiting for client"; + } + if(DialogWindows.Count > 0) + { + return DialogWindows.Count().ToString()+" Dialogs waiting"; + } + CleanUp(); + return "Active"; + } + + public string AvatarRelayTarget(UUID avatar) + { + lock (DialogRelayAvatars) + { + if (DialogRelayAvatars.Contains(avatar) == false) + { + DialogRelayAvatars.Add(avatar); + return "added"; + } + DialogRelayAvatars.Remove(avatar); + return "removed"; + } + } + + public string ChannelRelayTarget(int channel) + { + lock (DialogRelayChannels) + { + if (DialogRelayChannels.Contains(channel) == false) + { + DialogRelayChannels.Add(channel); + return "added"; + } + DialogRelayChannels.Remove(channel); + return "removed"; + } + } + + public string HttpRelayTarget(string url) + { + lock (DialogRelayHTTP) + { + if (DialogRelayHTTP.Contains(url) == false) + { + DialogRelayHTTP.Add(url); + return "added"; + } + DialogRelayHTTP.Remove(url); + return "removed"; + } + } + + public string DialogAction(int dialogID, string button) + { + lock(DialogWindows) + { + if(DialogWindows.ContainsKey(dialogID) == false) + { + return "Invaild dialog window"; + } + else if (DialogWindows[dialogID].ButtonLabels.Contains(button) == false) + { + return "Invaild dialog button"; + } + ScriptDialogEventArgs e = DialogWindows[dialogID]; + GetClient().Self.ReplyToScriptDialog(e.Channel, e.ButtonLabels.IndexOf(button), button, e.ObjectID); + DialogWindowsExpire.Remove(dialogID); + DialogWindows.Remove(dialogID); + return "action"; + } + } + + protected long lastclean = 0; + protected void CleanUp() + { + long dif = SecondbotHelpers.UnixTimeNow() - lastclean; + if(dif > 30) + { + lastclean = SecondbotHelpers.UnixTimeNow(); + lock(DialogWindows) + { + long unixtime = SecondbotHelpers.UnixTimeNow(); + List removeids = new List(); + foreach(KeyValuePair a in DialogWindowsExpire) + { + if(a.Value > unixtime) + { + removeids.Add(a.Key); + } + } + foreach(int id in removeids) + { + DialogWindowsExpire.Remove(id); + DialogWindows.Remove(id); + } + } + } + } + + protected void BotClientRestart(object o, BotClientNotice e) + { + Console.WriteLine("Dialog service [Attached to new client]"); + GetClient().Network.LoggedOut += BotLoggedOut; + GetClient().Network.SimConnected += BotLoggedIn; + } + + protected void BotLoggedOut(object o, LoggedOutEventArgs e) + { + GetClient().Network.SimConnected += BotLoggedIn; + Console.WriteLine("Dialog service [waiting for new client]"); + if (GetClient() != null) + { + GetClient().Self.ScriptDialog -= DialogWindowEvent; + } + } + + protected void BotLoggedIn(object o, SimConnectedEventArgs e) + { + GetClient().Network.SimConnected -= BotLoggedIn; + botConnected = true; + // attach events + GetClient().Self.ScriptDialog += DialogWindowEvent; + } + + protected Dictionary DialogWindows = new Dictionary(); + protected Dictionary DialogWindowsExpire = new Dictionary(); + protected int nextDialogWindow = 1; + protected List DialogRelayChannels = new List(); + protected List DialogRelayAvatars = new List(); + protected List DialogRelayHTTP = new List(); + protected UUID objectOwnerOnly = UUID.Zero; + + protected void DialogWindowEvent(object sender, ScriptDialogEventArgs e) + { + lock (DialogWindows) + { + if((objectOwnerOnly != UUID.Zero) && (objectOwnerOnly != e.OwnerID)) + { + return; + } + int windowid = nextDialogWindow; + nextDialogWindow++; + if(nextDialogWindow > 999) + { + nextDialogWindow = 1; + } + DialogWindows.Add(windowid, e); + DialogWindowsExpire.Add(windowid, SecondbotHelpers.UnixTimeNow() + 440); + DialogWindow window = new DialogWindow(); + window.buttons = e.ButtonLabels.ToArray(); + window.dialogid = windowid; + window.message = e.Message; + window.objectname = e.ObjectName; + string eventMessage = JsonConvert.SerializeObject(window); + foreach(int a in DialogRelayChannels) + { + if(a >= 0) + { + GetClient().Self.Chat(eventMessage, a, ChatType.Normal); + } + } + foreach(UUID av in DialogRelayAvatars) + { + GetClient().Self.InstantMessage(av, eventMessage); + } + // @todo add http output + } + } + + + + + public override void Start() + { + Stop(); + master.BotClientNoticeEvent += BotClientRestart; + } + + public override void Stop() + { + master.BotClientNoticeEvent -= BotClientRestart; + } + } + + public class DialogWindow + { + public string message; + public string[] buttons; + public string objectname; + public int dialogid; + } +}