diff --git a/Source/Bot/Data.cs b/Source/Bot/Data.cs index 636b2cd..c5eecb9 100644 --- a/Source/Bot/Data.cs +++ b/Source/Bot/Data.cs @@ -24,38 +24,24 @@ using CommandFuncDict = namespace ProjectGolan.Vrobot3 { - // - // BotCommand - // // Delegate type for bot commands. - // public delegate void BotCommand(User usr, Channel channel, String msg); - // - // CommandDict - // // Dictionary of bot commands. - // public class CommandDict : Dictionary {} - // - // Bot - // public partial class Bot { private readonly Dictionary lastLine; - private readonly IBotClient client; + private readonly Client.IChatClient client; public List modules { get; private set; } public CommandFuncDict cmdfuncs { get; private set; } public readonly BotInfo info; - public bool isInAudioChannel => client.isInAudioChannel(); - public BotClientInfo clientInfo => client.info; + public Client.ClientInfo clientInfo => client.info; + public Client.IChatClient getClient() => client; - // - // Bot constructor - // public Bot(BotInfo info) { this.info = info; @@ -65,8 +51,8 @@ namespace ProjectGolan.Vrobot3 switch(info.serverType) { - case "IRC": this.client = new BotClientIRC(this); break; - case "Discord": this.client = new BotClientDiscord(this); break; + case "IRC": this.client = new Client.ClientIRC(this); break; + case "Discord": this.client = new Client.ClientDiscord(this); break; default: throw new BotConfigurationException("Invalid server type."); } @@ -84,9 +70,6 @@ namespace ProjectGolan.Vrobot3 cmdfuncs.Add(kvp.Key, Tuple.Create(mod, kvp.Value)); } - // - // client - // public void connect() => client.connect(); public void action(Channel channel, String msg) => @@ -109,12 +92,6 @@ namespace ProjectGolan.Vrobot3 public void reply(User usr, ulong id, String msg) => message(id, usr.name + ": " + msg); - public void partAudioChannel() => client.partAudioChannel(); - public Task playAudioFile(String file) => client.playAudioFile(file); - - // - // disconnect - // public void disconnect() { cmdfuncs.Clear(); @@ -122,24 +99,6 @@ namespace ProjectGolan.Vrobot3 client.disconnect(); } - // - // joinAudioChannel - // - public async Task joinAudioChannel(User user) - { - var channel = client.getAudioChannel(user); - if(channel != null) - { - await client.joinAudioChannel(channel); - return true; - } - else - return false; - } - - // - // checkModPermissions - // public bool checkModPermissions(Channel channel, Type mod) { String[] enables; diff --git a/Source/Bot/PrivateFuncs.cs b/Source/Bot/PrivateFuncs.cs index 87a845f..68c189b 100644 --- a/Source/Bot/PrivateFuncs.cs +++ b/Source/Bot/PrivateFuncs.cs @@ -59,11 +59,11 @@ namespace ProjectGolan.Vrobot3 return false; if(attribute is BotModuleIRCAttribute && - !(client is BotClientIRC)) + !(client is Client.ClientIRC)) return false; if(attribute is BotModuleDiscordAttribute && - !(client is BotClientDiscord)) + !(client is Client.ClientDiscord)) return false; if(attribute is BotModuleRequiresAudioAttribute && diff --git a/Source/Client/Client.cs b/Source/Client/Client.cs index ee9bf52..91080ef 100644 --- a/Source/Client/Client.cs +++ b/Source/Client/Client.cs @@ -13,12 +13,9 @@ using System; using System.Threading.Tasks; -namespace ProjectGolan.Vrobot3 +namespace ProjectGolan.Vrobot3.Client { - // - // BotClientInfo - // - public class BotClientInfo + public class ClientInfo { public bool hasAudio; public bool hasColors; @@ -27,17 +24,14 @@ namespace ProjectGolan.Vrobot3 public bool shortMessages; } - // - // IBotClient - // - public abstract class IBotClient + public abstract class IChatClient { protected Bot bot; - public BotClientInfo info { get; protected set; } + public ClientInfo info { get; protected set; } - protected IBotClient(Bot bot) + protected IChatClient(Bot bot) { - this.info = new BotClientInfo(); + this.info = new ClientInfo(); this.bot = bot; } @@ -58,16 +52,6 @@ namespace ProjectGolan.Vrobot3 // user public abstract bool userPermitted(User usr, BotRole role); - - // audio - public virtual ChannelAudio getAudioChannel(User usr) => - new ChannelAudio(); - public virtual async Task joinAudioChannel(ChannelAudio channel) => - await Task.FromResult(0); - public virtual void partAudioChannel() {} - public virtual bool isInAudioChannel() => false; - public virtual async Task playAudioFile(String file) => - await Task.FromResult(0); } } diff --git a/Source/Client/Discord.cs b/Source/Client/Discord.cs index 31a2add..d348fed 100644 --- a/Source/Client/Discord.cs +++ b/Source/Client/Discord.cs @@ -15,24 +15,15 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Diagnostics; -using Discord.Audio; -namespace ProjectGolan.Vrobot3 +namespace ProjectGolan.Vrobot3.Client { - // - // BotClientDiscord - // - public class BotClientDiscord : IBotClient + public class ClientDiscord : IChatClient { - private Discord.DiscordClient client; - private Discord.Audio.IAudioClient audioClient; - private Discord.Server server; + public Discord.DiscordClient client; + public Discord.Server server; - // - // BotClientDiscord constructor - // - public BotClientDiscord(Bot bot) : - base(bot) + public ClientDiscord(Bot bot) : base(bot) { this.client = new Discord.DiscordClient(); @@ -61,24 +52,16 @@ namespace ProjectGolan.Vrobot3 bot.onMessage(usr, channel, evt.Message.Text); } }; - - this.client.UsingAudio(x => x.Mode = AudioMode.Outgoing); } - // - // getUser - // - private Discord.User getUser(User usr) + public Discord.User getUser(User usr) { if(server == null) server = client.GetServer(ulong.Parse(bot.info.serverAddr)); return server.GetUser(ulong.Parse(usr.hostname)); } - // - // checkRole - // - private bool checkRole(User usr, String[] strings) + public bool checkRole(User usr, String[] strings) { var duser = getUser(usr); @@ -102,9 +85,6 @@ namespace ProjectGolan.Vrobot3 return false; } - // - // connect - // public override void connect() { Console.WriteLine("{0}: Creating connection.", bot.info.serverName); @@ -115,42 +95,26 @@ namespace ProjectGolan.Vrobot3 }); } - // - // disconnect - // public override void disconnect() { if(client != null) { - partAudioChannel(); client.Disconnect(); client = null; } } - // - // sendAction - // public override void sendAction(Channel channel, String msg) => client.GetChannel(channel.id)?.SendMessage( - "_" + Discord.Format.Escape(msg) + "_"); + "_" + Discord.Format.Escape(msg ?? String.Empty) + "_"); - // - // sendMessage - // public override void sendMessage(Channel channel, String msg) => - client.GetChannel(channel.id)?.SendMessage(Discord.Format.Escape(msg)); + client.GetChannel(channel.id)?.SendMessage(Discord.Format.Escape(msg ?? String.Empty)); - // - // sendMessageRaw - // public override void sendMessageRaw(Channel channel, String msg) => sendMessage(channel, "```" + Discord.Format.Escape(msg ?? String.Empty) + "```"); - // - // getChannel - // public override Channel getChannel(ulong id) { var dchannel = client.GetChannel(id); @@ -160,104 +124,10 @@ namespace ProjectGolan.Vrobot3 return channel; } - // - // userPermitted - // public override bool userPermitted(User usr, BotRole role) => role == BotRole.User || (role == BotRole.HalfAdmin && checkRole(usr, bot.info.roles.halfadmin)) || (role == BotRole.Admin && checkRole(usr, bot.info.roles.admin)); - - // - // getAudioChannel - // - public override ChannelAudio getAudioChannel(User usr) - { - var dchannel = getUser(usr).VoiceChannel; - if(dchannel == null) return null; - var channel = new ChannelAudio{}; - channel.id = dchannel.Id; - channel.name = dchannel.Name; - return channel; - } - - // - // joinAudioChannel - // - public override async Task joinAudioChannel(ChannelAudio channel) - { - if(channel == null) - return; - - var dchannel = client.GetChannel(channel.id); - if(!isInAudioChannel()) - audioClient = await dchannel.JoinAudio(); - else - await audioClient.Join(dchannel); - } - - // - // partAudioChannel - // - public override void partAudioChannel() - { - if(isInAudioChannel()) - { - audioClient.Clear(); - audioClient.Wait(); - audioClient.Disconnect(); - } - audioClient = null; - } - - // - // isInAudioChannel - // - public override bool isInAudioChannel() => - audioClient?.State == Discord.ConnectionState.Connected; - - // - // playAudioFile - // - public override async Task playAudioFile(String file) - { - if(!isInAudioChannel()) return; - - var proc = Process.Start(new ProcessStartInfo{ - FileName = "ffmpeg", - Arguments = $"-i {file} -f s16le -ar 48000 -ac 2 " + - "-loglevel quiet pipe:1", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = false, - CreateNoWindow = true - }); - - var buf = new byte[3840 * 32]; - var ostream = audioClient.OutputStream; - var istream = proc?.StandardOutput.BaseStream; - - try - { - int count; - while(proc?.HasExited == false && - (count = await istream.ReadAsync(buf, 0, buf.Length)) != 0) - { - Thread.Sleep(8); - await ostream.WriteAsync(buf, 0, count); - } - } - catch(OperationCanceledException) - { - Console.WriteLine("{0}: Canceled audio stream.", - bot.info.serverName); - } - finally - { - istream?.Dispose(); - ostream.Dispose(); - } - } } } diff --git a/Source/Client/IRC.cs b/Source/Client/IRC.cs index 270e260..55175e4 100644 --- a/Source/Client/IRC.cs +++ b/Source/Client/IRC.cs @@ -12,18 +12,11 @@ using System; -namespace ProjectGolan.Vrobot3 +namespace ProjectGolan.Vrobot3.Client { - // - // BotClientIRC - // - public class BotClientIRC : IBotClient + public class ClientIRC : IChatClient { - // - // BotClientIRC constructor - // - public BotClientIRC(Bot bot) : - base(bot) + public ClientIRC(Bot bot) : base(bot) { this.info.hasAudio = false; this.info.hasColors = true; diff --git a/Source/Modules/Mod_Audio.cs b/Source/Modules/Mod_Audio.cs deleted file mode 100644 index 80e1561..0000000 --- a/Source/Modules/Mod_Audio.cs +++ /dev/null @@ -1,185 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright © 2016 Project Golan -// -// See "LICENSE" for more information. -// -//----------------------------------------------------------------------------- -// -// Audio-based commands. -// -//----------------------------------------------------------------------------- - -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Collections.Generic; - -namespace ProjectGolan.Vrobot3.Modules -{ - // - // Mod_Audio - // - [BotModuleRequiresAudio, BotModuleDisabled] - public class Mod_Audio : IBotModule - { - // - // QueueItem - // - class QueueItem - { - private Utils.URI uri; - - public QueueItem(Utils.URI uri) - { - this.uri = uri; - } - - public override String ToString() => String.Empty; - } - - // - // Queue - // - class Queue - { - private TimeSpan curTime; - private List items; - private int pos; - - public Queue() - { - this.curTime = new TimeSpan(); - this.items = new List(); - this.pos = 0; - } - - public bool addItem(Utils.URI uri) - { - var item = new QueueItem(uri); - items.Add(item); - return true; - } - } - - private readonly String[] validMethods = - { "http", "https", "ftp", "ftps" }; - private Queue queue = new Queue(); - - // - // Mod_Audio constructor - // - public Mod_Audio(Bot bot_) : - base(bot_) - { - commands["queue"] = new BotCommandStructure{ - cmd = cmdQueue, - help = "Add an item (or items) to the audio queue.\n" + - "Syntax: .queue uri...\n" + - "Example: .queue https://www.youtube.com/watch?v=13pL0TiOiHM" - }; - - commands["play"] = new BotCommandStructure{ - cmd = cmdPlay, - help = "Set the currently playing item in the queue. " + - "If a URL is given, queues and plays that.\n" + - "Syntax: .play [number|uri]\n" + - "Example: .play 5\n" + - "Example: .play https://www.youtube.com/watch?v=13pL0TiOiHM" - }; - - commands["lsqueue"] = new BotCommandStructure{ - cmd = cmdListQueue, - help = "Lists queue items.\n" + - "Syntax: .lsqueue" - }; - - commands["summon"] = new BotCommandStructure{ - cmd = cmdSummon, - help = "Makes the bot join your audio channel.\n" + - "Syntax: .summon" - }; - - commands["vanquish"] = new BotCommandStructure{ - cmd = cmdVanquish, - help = "Makes the bot leave their audio channel.\n" + - "Syntax: %vanquish", - role = BotRole.HalfAdmin - }; - } - - // - // summon - // - private async Task summon(User usr, Channel channel) - { - if(bot.isInAudioChannel) - return true; - - if(!await bot.joinAudioChannel(usr)) - { - bot.reply(usr, channel, - "Couldn't find audio channel. " + - "If you are already in an audio channel, please reconnect to " + - "it and try again."); - return false; - } - - return true; - } - - // - // cmdQueue - // - public void cmdQueue(User usr, Channel channel, String msg) - { - var uris = Utils.URI.Matches(msg); - - if(uris == null) - throw new CommandArgumentException("no valid URIs"); - - int loadPass = 0; - foreach(var uri_ in uris) - { - var uri = uri_; - if(uri.method == String.Empty) - uri.method = "http"; - - if(validMethods.Contains(uri.method) && - queue.addItem(uri)) - loadPass++; - } - - bot.reply(usr, channel, - $"Added {loadPass} item{loadPass != 1 ? "s" : ""} to the queue."); - } - - // - // cmdPlay - // - public void cmdPlay(User usr, Channel channel, String msg) - { - } - - // - // cmdListQueue - // - public void cmdListQueue(User usr, Channel channel, String msg) - { - } - - // - // cmdSummon - // - public void cmdSummon(User usr, Channel channel, String msg) => - summon(usr, channel); - - // - // cmdVanquish - // - public void cmdVanquish(User usr, Channel channel, String msg) => - bot.partAudioChannel(); - } -} - diff --git a/Source/Modules/Mod_DiscordLogger.cs b/Source/Modules/Mod_DiscordLogger.cs new file mode 100644 index 0000000..2169cea --- /dev/null +++ b/Source/Modules/Mod_DiscordLogger.cs @@ -0,0 +1,294 @@ +//----------------------------------------------------------------------------- +// +// Copyright © 2016 Project Golan +// +// See "LICENSE" for more information. +// +//----------------------------------------------------------------------------- +// +// Logging. +// +//----------------------------------------------------------------------------- + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Threading.Tasks; + +delegate void HaxFn(String name, String vname); + +namespace ProjectGolan.Vrobot3.Modules +{ + [BotModuleDiscord] + public class Mod_DiscordLogger : IBotModule + { + public Mod_DiscordLogger(Bot bot) : base(bot) + { + var client = bot.getClient() as Client.ClientDiscord; + + client.client.ChannelCreated += + catchFunc( + async (_, e) => + await logMsg(e.Server, "Channel created", getChannel(e.Channel))); + + client.client.ChannelDestroyed += + catchFunc( + async (_, e) => + await logMsg(e.Server, "Channel destroyed", getChannel(e.Channel))); + + client.client.ChannelUpdated += + catchFunc(async (_, e) => + { + var delta = getChannelDelta(e.Before, e.After); + if(delta != String.Empty) + await logMsg(e.Server, "Channel updated", delta); + }); + + client.client.MessageDeleted += + catchFunc(async (_, e) => + { + if(!e.Message.User.IsBot) + await verMsg(e.Server, "Message deleted", getMessage(e.Message)); + }); + + client.client.MessageUpdated += + catchFunc(async (_, e) => + { + var delta = getMessageDelta(e.Before, e.After); + if(delta != String.Empty) + await verMsg(e.Server, "Message edited", delta); + }); + + client.client.UserBanned += + catchFunc(async (_, e) => + await logMsg(e.Server, "User banned", getUser(e.User))); + + client.client.UserUnbanned += + catchFunc(async (_, e) => + await logMsg(e.Server, "User unbanned", getUser(e.User))); + + client.client.UserJoined += + catchFunc(async (_, e) => + await logMsg(e.Server, "User joined", getUser(e.User))); + + client.client.UserLeft += + catchFunc(async (_, e) => + await logMsg(e.Server, "User removed", getUser(e.User))); + + client.client.UserUpdated += + catchFunc(async (_, e) => + { + var delta = getUserDelta(e.Before, e.After); + if(delta != String.Empty) + await verMsg(e.Server, "User updated", delta); + }); + } + + private EventHandler catchFunc(EventHandler fn) + { + return (object sender, T evt) => + { + try + {fn(sender, evt);} + catch(System.Exception) + {} + }; + } + + private String yesno(bool arg) => arg ? "Yes" : "No"; + + private String getTime(DateTime time) + { + var offs = TimeZoneInfo.Local.GetUtcOffset(time); + return $"{time.ToShortDateString()} {time.ToLongTimeString()} " + + $"UTC{offs.Hours.ToString("+#;-#;0")}:{offs.Minutes}"; + } + + private String discordEscape(String str) => + Discord.Format.Escape(str ?? String.Empty); + + private String getChannel(Discord.Channel channel) => + $"`Name :` {discordEscape(channel.Name)}\n" + + $"`Topic :` {discordEscape(channel.Topic)}\n" + + $"`Id :` `{channel.Id}`\n" + + $"`Position :` `{channel.Position}`\n" + + $"`Type :` {channel.Type.ToString()}"; + + private String getUser(Discord.User user) => + $"`Username :` {discordEscape(user.Name)}\n" + + $"`Nickname :` {discordEscape(user.Nickname)}\n" + + $"`Id :` `{user.Id}`\n" + + $"`Is Bot :` {yesno(user.IsBot)}\n" + + $"`Joined At :` {getTime(user.JoinedAt)}"; + + private String getMessage(Discord.Message msg) => + $"`Time Sent :` {getTime(msg.Timestamp)}\n" + + $"`Channel :` {discordEscape(msg.Channel.Name)}\n" + + $"`Id :` `{msg.Id}`\n" + + $"`Content :` {msg.Text}\n" + + $"\nUser info:\n{getUser(msg.User)}"; + + private String getMessageDelta(Discord.Message bfr, Discord.Message aft) + { + if(bfr.Text == aft.Text) return String.Empty; + return $"`Time Sent :` {getTime(aft.Timestamp)}\n" + + $"`Channel :` {discordEscape(aft.Channel.Name)}\n" + + $"`Id :` `{aft.Id}`\n" + + $"`Old Content :` {bfr.Text}\n" + + $"`New Content :` {aft.Text}\n" + + $"\nUser info:\n{getUser(aft.User)}"; + } + + private String getPermDelta(Discord.ServerPermissions bfr, + Discord.ServerPermissions aft) + { + var outp = String.Empty; + + if(bfr.RawValue != aft.RawValue) + { + outp += $"`Old Value :` `{bfr.RawValue}`\n"; + outp += $"`New Value :` `{aft.RawValue}`\n"; + + HaxFn fn = (String name, String vname) => { + var a = (bool)typeof(Discord.ServerPermissions) + .GetProperty(vname).GetValue(bfr); + var b = (bool)typeof(Discord.ServerPermissions) + .GetProperty(vname).GetValue(aft); + if(a != b) + outp += $"`{name}:` {yesno(b)}\n"; + }; + + fn("Create Invite", "CreateInstantInvite"); + fn("Ban Users ", "BanMembers"); + fn("Kick Users ", "KickMembers"); + fn("Edit Channels", "ManageChannels"); + fn("Edit Server ", "ManageServer"); + fn("Join Channels", "ReadMessages"); + fn("Send Messages", "SendMessages"); + fn("Send TTS ", "SendTTSMessages"); + fn("Edit Messages", "ManageMessages"); + fn("Embed Links ", "EmbedLinks"); + fn("Attach Files ", "AttachFiles"); + fn("Ping Everyone", "MentionEveryone"); + fn("Join Voice ", "Connect"); + fn("Speak ", "Speak"); + fn("Mute Users ", "MuteMembers"); + fn("Deafen Users ", "DeafenMembers"); + fn("Move Users ", "MoveMembers"); + fn("Use VA ", "UseVoiceActivation"); + fn("Change Nick ", "ChangeNickname"); + fn("Edit Nicks ", "ManageNicknames"); + fn("Edit Roles ", "ManageRoles"); + } + return outp; + } + + private String getChannelDelta(Discord.Channel bfr, Discord.Channel aft) + { + var outp1 = String.Empty; + var outp2 = String.Empty; + if(bfr.Name != aft.Name) + { + outp1 += "Name changed.\n"; + if(!String.IsNullOrEmpty(bfr.Name)) + outp2 += $"`Old Name :` {discordEscape(bfr.Name)}\n"; + if(!String.IsNullOrEmpty(aft.Name)) + outp2 += $"`New Name :` {discordEscape(aft.Name)}\n"; + } + if(bfr.Id != aft.Id) + { + outp1 += "Id changed.\n"; + outp2 += $"`Old Id :` `{bfr.Id}`\n"; + outp2 += $"`New Id :` `{aft.Id}`\n"; + } + if(bfr.Topic != aft.Topic) + { + outp1 += "Topic changed.\n"; + if(!String.IsNullOrEmpty(bfr.Topic)) + outp2 += $"`Old Topic :` {discordEscape(bfr.Topic)}\n"; + if(!String.IsNullOrEmpty(aft.Topic)) + outp2 += $"`New Topic :` {discordEscape(aft.Topic)}\n"; + } + if(bfr.Position != aft.Position) + { + outp1 += "Position changed.\n"; + outp2 += $"`Old Position :` `{bfr.Position}`\n"; + outp2 += $"`New Position :` `{aft.Position}`\n"; + } + if(outp1 != String.Empty) + outp2 += $"\nChannel info:\n{getChannel(aft)}\n"; + return outp1 + outp2.Trim(); + } + + private String getUserDelta(Discord.User bfr, Discord.User aft) + { + var outp1 = String.Empty; + var outp2 = String.Empty; + var perm = getPermDelta(bfr.ServerPermissions, aft.ServerPermissions); + if(bfr.Name != aft.Name) + { + outp1 += "Username changed.\n"; + if(!String.IsNullOrEmpty(bfr.Name)) + outp2 += $"`Old Username :` {discordEscape(bfr.Name)}\n"; + if(!String.IsNullOrEmpty(aft.Name)) + outp2 += $"`New Username :` {discordEscape(aft.Name)}\n"; + } + if(bfr.Nickname != aft.Nickname) + { + outp1 += "Nickname changed.\n"; + if(!String.IsNullOrEmpty(bfr.Nickname)) + outp2 += $"`Old Nickname :` {discordEscape(bfr.Nickname)}\n"; + if(!String.IsNullOrEmpty(aft.Nickname)) + outp2 += $"`New Nickname :` {discordEscape(aft.Nickname)}\n"; + } + if(bfr.AvatarId != aft.AvatarId) + { + outp1 += "Avatar changed.\n"; + outp2 += $"`Old Avatar Id:` `{bfr.AvatarId}`\n"; + outp2 += $"`New Avatar Id:` `{aft.AvatarId}`\n"; + outp2 += $"`Old AvatarUrl:` `{bfr.AvatarUrl}`\n"; + outp2 += $"`New AvatarUrl:` `{aft.AvatarUrl}`\n"; + } + if(bfr.Discriminator != aft.Discriminator) + { + outp1 += "Unique Id changed.\n"; + outp2 += $"`Old Unique Id:` `{bfr.Discriminator}`\n"; + outp2 += $"`New Unique Id:` `{aft.Discriminator}`\n"; + } + if(bfr.Id != aft.Id) + { + outp1 += "Id changed.\n"; + outp2 += $"`Old Id :` `{bfr.Id}`\n"; + outp2 += $"`New Id :` `{aft.Id}`\n"; + } + if(!String.IsNullOrEmpty(perm)) + { + outp1 += "Permissions changed.\n"; + outp2 += perm; + } + if(outp1 != String.Empty) + outp2 += $"\nUser info:\n{getUser(aft)}\n"; + return outp1 + outp2.Trim(); + } + + private async Task sndMsg(Discord.Server server, String name, + String type, String msg) + { + if(server.Id.ToString() != bot.info.serverAddr) return; + var log = server.FindChannels(name).FirstOrDefault(); + if(log == null) return; + var time = getTime(DateTime.Now); + if(msg.Length > 1800) + await log.SendMessage($"{type} at {time}\n[Omitted, too long]"); + else + await log.SendMessage($"{type} at {time}\n{msg}"); + } + + private async Task logMsg(Discord.Server server, String type, String msg) + => await sndMsg(server, "log", type, msg); + + private async Task verMsg(Discord.Server server, String type, String msg) + => await sndMsg(server, "log-v", type, msg); + } +} + diff --git a/vrobot3.csproj b/vrobot3.csproj index 1e3f7ca..753c978 100644 --- a/vrobot3.csproj +++ b/vrobot3.csproj @@ -79,7 +79,7 @@ - +