diff --git a/BSBshared/IO/SimpleIO.cs b/BSBshared/IO/SimpleIO.cs index 50e65c0..961e90c 100644 --- a/BSBshared/IO/SimpleIO.cs +++ b/BSBshared/IO/SimpleIO.cs @@ -67,8 +67,20 @@ namespace BetterSecondBotShared.IO { serializer.Serialize(writer, tokensfile); } + } + + public void WriteJsonRelays(JsonCustomRelays relays, string targetfile) + { + JsonSerializer serializer = new JsonSerializer(); + using (StreamWriter sw = new StreamWriter(@"" + root_folder + "" + targetfile)) + using (JsonWriter writer = new JsonTextWriter(sw) { Formatting = Formatting.Indented }) + { + serializer.Serialize(writer, relays); + } } + + public void makeOld(string targetfile) { System.IO.File.Move(@""+root_folder + "" + targetfile, @"" + root_folder + "" + targetfile+".old"); diff --git a/BSBshared/Json/JsonConfig.cs b/BSBshared/Json/JsonConfig.cs index 5861e2a..398699d 100644 --- a/BSBshared/Json/JsonConfig.cs +++ b/BSBshared/Json/JsonConfig.cs @@ -15,6 +15,11 @@ namespace BetterSecondBotShared.Json public string[] CustomCommands { get; set; } } + public class JsonCustomRelays + { + public string[] CustomRelays { get; set; } + } + public class JsonConfig { diff --git a/CLI/BetterRelayService/BetterRelay.cs b/CLI/BetterRelayService/BetterRelay.cs new file mode 100644 index 0000000..b34ba78 --- /dev/null +++ b/CLI/BetterRelayService/BetterRelay.cs @@ -0,0 +1,253 @@ +using BetterSecondBot.DiscordSupervisor; +using BetterSecondBotShared.IO; +using BetterSecondBotShared.Json; +using BetterSecondBotShared.Static; +using BSB.bottypes; +using Newtonsoft.Json; +using OpenMetaverse; +using System; +using System.Collections.Generic; +using System.Text; + +namespace BetterSecondBot.BetterRelayService +{ + public class BetterRelay + { + Discord_super superV = null; + CliExitOnLogout controler = null; + + List DiscordRelay = new List(); + List LocalchatRelay = new List(); + List ObjectIMRelay = new List(); + List AvatarIMRelay = new List(); + List GroupChatRelay = new List(); + + public BetterRelay(CliExitOnLogout setcontroler, Discord_super setdiscord, bool running_in_docker) + { + controler = setcontroler; + superV = setdiscord; + if(running_in_docker == true) + { + loadRelayConfigFromENV(); + } + else + { + loadRelayConfigFromFile(); + } + attach_events(); + } + + protected void ApplyRelayConfig(string raw) + { + string[] bits = raw.Split(","); + bool have_source_type = false; + bool have_source_filter = false; + bool have_target_type = false; + bool have_target_filter = false; + if(bits.Length == 4) + { + relay_config relay = new relay_config(); + foreach (string a in bits) + { + string[] subbits = a.Split(":"); + if(subbits.Length == 2) + { + if(subbits[0] == "source-type") + { + have_source_type = true; + relay.sourcename = subbits[1]; + } + else if (subbits[0] == "source-filter") + { + have_source_filter = true; + relay.sourcevalue = subbits[1]; + } + else if (subbits[0] == "target-type") + { + have_target_type = true; + relay.targetname = subbits[1]; + } + else if (subbits[0] == "target-config") + { + have_target_filter = true; + relay.targetvalue = subbits[1]; + } + } + } + List tests = new List() { have_source_type, have_source_filter, have_target_type, have_target_filter }; + if(tests.Contains(false) == false) + { + if (relay.sourcename == "localchat") LocalchatRelay.Add(relay); + else if (relay.sourcename == "groupchat") GroupChatRelay.Add(relay); + else if (relay.sourcename == "avatarim") AvatarIMRelay.Add(relay); + else if (relay.sourcename == "objectim") ObjectIMRelay.Add(relay); + else if (relay.sourcename == "discord") DiscordRelay.Add(relay); + } + } + } + + protected void loadRelayConfigFromENV() + { + int loop = 1; + bool found = true; + while (found == true) + { + if (helpers.notempty(Environment.GetEnvironmentVariable("customrelay_" + loop.ToString())) == true) + { + ApplyRelayConfig(Environment.GetEnvironmentVariable("customrelay_" + loop.ToString())); + } + else + { + found = false; + } + loop++; + } + } + + + + protected void loadRelayConfigFromFile() + { + JsonCustomRelays LoadedRelays = new JsonCustomRelays + { + CustomRelays = new string[] { "source-type:discord,source-filter:123451231235@12351312321,target-type:localchat,target-config:0" } + }; + string targetfile = "customrelays.json"; + SimpleIO io = new SimpleIO(); + if (SimpleIO.FileType(targetfile, "json") == false) + { + io.WriteJsonRelays(LoadedRelays, targetfile); + return; + } + if (io.Exists(targetfile) == false) + { + io.WriteJsonRelays(LoadedRelays, targetfile); + return; + } + string json = io.ReadFile(targetfile); + if (json.Length > 0) + { + try + { + LoadedRelays = JsonConvert.DeserializeObject(json); + foreach (string loaded in LoadedRelays.CustomRelays) + { + ApplyRelayConfig(loaded); + } + } + catch + { + io.makeOld(targetfile); + io.WriteJsonRelays(LoadedRelays, targetfile); + } + return; + } + } + + public void unattach_events() + { + controler.Bot.MessageEvent -= SLMessageHandler; + superV.MessageEvent -= DiscordMessageHandler; + } + + protected void attach_events() + { + controler.Bot.MessageEvent += SLMessageHandler; + superV.MessageEvent += DiscordMessageHandler; + } + + protected async void TriggerRelay(string sourcetype, string name,string message, string filtervalue) + { + List Dataset = new List(); + if (sourcetype == "localchat") Dataset = LocalchatRelay; + else if (sourcetype == "groupchat") Dataset = GroupChatRelay; + else if (sourcetype == "avatarim") Dataset = AvatarIMRelay; + else if (sourcetype == "objectim") Dataset = ObjectIMRelay; + else if (sourcetype == "discord") Dataset = DiscordRelay; + if(message.Contains("[relay]") == true) + { + return; + } + message = "[relay] " + sourcetype + " # " + name + ": " + message; + foreach (relay_config cfg in Dataset) + { + if (((cfg.sourcevalue == "all") && (sourcetype != "discordchat")) || (cfg.sourcevalue == filtervalue)) + { + if (cfg.targetname == "discord") + { + string[] cfga = cfg.targetvalue.Split("@"); + if (cfga.Length == 2) + { + if ((cfga[0] + "@" + cfga[1]) != filtervalue) + { + await controler.Bot.SendMessageToDiscord(cfga[0], cfga[1], message, false); + } + } + } + else if (cfg.targetname == "localchat") + { + int chan = 0; + int.TryParse(cfg.targetvalue, out chan); + controler.Bot.GetClient.Self.Chat(message, chan, ChatType.Normal); + } + else if (cfg.targetname == "avatarchat") + { + if (cfg.targetvalue != filtervalue) + { + if (UUID.TryParse(cfg.targetvalue, out UUID target) == true) + { + controler.Bot.SendIM(target, message); + } + } + } + else if (cfg.targetname == "groupchat") + { + if (cfg.targetvalue != filtervalue) + { + controler.Bot.GetCommandsInterface.Call("Groupchat", cfg.targetvalue + "~#~" + message, UUID.Zero, "~#~"); + } + } + } + } + } + + protected void DiscordMessageHandler(object sender, DiscordMessageEvent e) + { + TriggerRelay("discord", e.name, e.message, "" + e.server.ToString() + "@" + e.channel.ToString()); + } + + protected void SLMessageHandler(object sender, MessageEventArgs e) + { + if (e.fromme == false) + { + if (e.localchat == true) + { + TriggerRelay("localchat", e.sender_name, e.message, e.sender_uuid.ToString()); + } + else if (e.avatar == false) + { + TriggerRelay("objectim", e.sender_name, e.message, e.sender_uuid.ToString()); + } + else if (e.group == true) + { + TriggerRelay("groupchat", e.sender_name, e.message, e.group_uuid.ToString()); + } + else if (e.avatar == true) + { + TriggerRelay("avatarim", e.sender_name, e.message, e.sender_uuid.ToString()); + } + } + + } + + } + + + public class relay_config + { + public string sourcename = ""; + public string sourcevalue = ""; + public string targetname = ""; + public string targetvalue = ""; + } +} diff --git a/CLI/DiscordSupervisor/Discord-super.cs b/CLI/DiscordSupervisor/Discord-super.cs index 3a2e9f6..e6fcff5 100644 --- a/CLI/DiscordSupervisor/Discord-super.cs +++ b/CLI/DiscordSupervisor/Discord-super.cs @@ -1,4 +1,5 @@ -using BetterSecondBotShared.Json; +using BetterSecondBot.BetterRelayService; +using BetterSecondBotShared.Json; using BetterSecondBotShared.logs; using System; using System.Collections.Generic; @@ -10,6 +11,7 @@ namespace BetterSecondBot.DiscordSupervisor public class Discord_super : DiscordEvents { protected int warmup = 0; + protected BetterRelay relayService; protected override void keep_alive() { while (exit_super == false) @@ -67,12 +69,21 @@ namespace BetterSecondBot.DiscordSupervisor protected override void login_bot(bool self_keep_alive) { - if (controler == null) + if(relayService != null) { - controler = new CliExitOnLogout(myconfig, running_as_docker, self_keep_alive); - controler.Bot.setDiscordClient(DiscordClient); - attach_events(); + relayService.unattach_events(); + relayService = null; } + if (controler != null) + { + unattach_events(); + controler.Bot.KillMePlease(); + controler = null; + } + controler = new CliExitOnLogout(myconfig, running_as_docker, self_keep_alive); + controler.Bot.setDiscordClient(DiscordClient); + relayService = new BetterRelay(controler, this, running_as_docker); + attach_events(); } } diff --git a/CLI/DiscordSupervisor/DiscordEvents.cs b/CLI/DiscordSupervisor/DiscordEvents.cs index eb8b961..6c6e5cb 100644 --- a/CLI/DiscordSupervisor/DiscordEvents.cs +++ b/CLI/DiscordSupervisor/DiscordEvents.cs @@ -16,6 +16,14 @@ namespace BetterSecondBot.DiscordSupervisor controler.Bot.SendImEvent += SendImHandler; } + protected void unattach_events() + { + controler.Bot.MessageEvent -= BotChatControlerHandler; + controler.Bot.StatusMessageEvent -= StatusMessageHandler; + controler.Bot.GroupsReadyEvent -= GroupsReadyHandler; + controler.Bot.SendImEvent -= SendImHandler; + } + protected void SendImHandler(object sender, ImSendArgs e) { if (controler.Bot.AvatarKey2Name.ContainsKey(e.avataruuid) == true) diff --git a/CLI/DiscordSupervisor/Inbound.cs b/CLI/DiscordSupervisor/Inbound.cs index a9cd264..931a704 100644 --- a/CLI/DiscordSupervisor/Inbound.cs +++ b/CLI/DiscordSupervisor/Inbound.cs @@ -9,8 +9,39 @@ using System.Threading; namespace BetterSecondBot.DiscordSupervisor { + + public class DiscordMessageEvent : EventArgs + { + public ulong channel { get; } + public ulong server { get; } + public string name { get; } + public string message { get; } + + public DiscordMessageEvent(ulong server, ulong channel, string name,string message) + { + this.channel = channel; + this.server = server; + this.name = name; + this.message = message; + } + } + public abstract class DiscordInbound : DiscordRelay { + private EventHandler _MessageEvent; + private readonly object _MessageEventLock = new object(); + public event EventHandler MessageEvent + { + add { lock (_MessageEventLock) { _MessageEvent += value; } } + remove { lock (_MessageEventLock) { _MessageEvent -= value; } } + } + protected void On_MessageEvent(DiscordMessageEvent e) + { + EventHandler handler = _MessageEvent; + handler?.Invoke(this, e); + } + + protected async Task InboundLocalchatMessage(IUserMessage message) { if (HasBot() == true) @@ -275,6 +306,7 @@ namespace BetterSecondBot.DiscordSupervisor if (message.Author.IsBot == false) { ITextChannel Chan = (ITextChannel)message.Channel; + On_MessageEvent(new DiscordMessageEvent(Chan.GuildId, Chan.Id, message.Author.Username, message.Content)); if (message.Content.StartsWith("!clear") == true) { await CleanDiscordChannel(Chan, 0, true).ConfigureAwait(false); diff --git a/Core/Commands/DiscordAPI/MessageChannel.cs b/Core/Commands/DiscordAPI/MessageChannel.cs index 82dd358..70fa86f 100644 --- a/Core/Commands/DiscordAPI/MessageChannel.cs +++ b/Core/Commands/DiscordAPI/MessageChannel.cs @@ -32,34 +32,12 @@ namespace BSB.Commands.DiscordAPI protected async Task MessageChannel(string[] args) { - DiscordSocketClient Discord = bot.getDiscordClient(); - if (ulong.TryParse(args[1], out ulong serverid) == true) + bool useTTS = false; + if (args.Length == 5) { - if (ulong.TryParse(args[2], out ulong channelid) == true) - { - bool useTTS = false; - if(args.Length == 5) - { - bool.TryParse(args[4], out useTTS); - } - SocketGuild server = Discord.GetGuild(serverid); - SocketTextChannel Channel = null; - foreach (SocketTextChannel channel in server.TextChannels) - { - if(channel.Id == channelid) - { - Channel = channel; - break; - } - } - if(Channel != null) - { - await Channel.SendMessageAsync(args[3], useTTS); - return true; - } - } + bool.TryParse(args[4], out useTTS); } - return false; + return await bot.SendMessageToDiscord(args[1], args[2], args[3], useTTS); } } } diff --git a/Core/bottypes/SecondBot.cs b/Core/bottypes/SecondBot.cs index 442565b..22b4921 100644 --- a/Core/bottypes/SecondBot.cs +++ b/Core/bottypes/SecondBot.cs @@ -67,5 +67,8 @@ namespace BSB.bottypes } } } + + + } } diff --git a/Core/bottypes/VirtualsBot.cs b/Core/bottypes/VirtualsBot.cs index aef9599..e054d79 100644 --- a/Core/bottypes/VirtualsBot.cs +++ b/Core/bottypes/VirtualsBot.cs @@ -5,14 +5,44 @@ using System; using System.Collections.Generic; using System.Text; using Discord; - +using System.Threading.Tasks; + namespace BSB.bottypes { public abstract class VirtualsBot : Log2FileBot { #region DiscordOutputTarget protected DiscordSocketClient DiscordLink = null; - protected string DiscordReadyWhyFailed = ""; + protected string DiscordReadyWhyFailed = ""; + public async Task SendMessageToDiscord(string target_serverid, string target_channelid, string message, bool useTTS) + { + if (discordReady() == true) + { + DiscordSocketClient Discord = getDiscordClient(); + if (ulong.TryParse(target_serverid, out ulong serverid) == true) + { + if (ulong.TryParse(target_channelid, out ulong channelid) == true) + { + SocketGuild server = Discord.GetGuild(serverid); + SocketTextChannel Channel = null; + foreach (SocketTextChannel channel in server.TextChannels) + { + if (channel.Id == channelid) + { + Channel = channel; + break; + } + } + if (Channel != null) + { + await Channel.SendMessageAsync(message, useTTS); + return true; + } + } + } + } + return false; + } public void setDiscordClient(DiscordSocketClient GivenDiscordLink) { DiscordLink = GivenDiscordLink; diff --git a/README.md b/README.md index 723cd50..53f1c17 100644 --- a/README.md +++ b/README.md @@ -138,3 +138,55 @@ You get set these tokens up by file or Environment Variables. core/walkto core/teleport core/gesture + + + +### BetterRelay system +--- +this is to replace the old broken relay thats currently built into the bot + + +> customrelay_1 = "source-type:discord,source-filter:123451231235@12351312321,target-type:localchat,target-config:4" +> customrelay_2 = "source-type:discord,source-filter:123451231235@12351312321,target-type:localchat,target-config:4" + +or via the config file +customrelays + +>{ +>"CustomRelays": [ +> source-type:discord,source-filter:123451231235@12351312321,target-type:chat,target-config:4 +>] +} + +to config the relay please use the settings below + + + source-type + discord + source-filter: serverid@serverchannel + + localchat + source-filter: talker uuid or "all" + + avatarim + source-filter: avatar uuid or "all" + + objectim + source-filter: object uuid or "all" + + groupchat + source-filter: group uuid or "all" + + + source-type + discord + target-config: serverid@serverchannel + + localchat + target-config: channel (default is 0) + + avatarchat + target-config: avatar uuid + + groupchat + target-config: group uuid \ No newline at end of file