diff --git a/Examples/config/TeamsLogger.json b/Examples/config/TeamsLogger.json index 55be96a..8d84d74 100644 --- a/Examples/config/TeamsLogger.json +++ b/Examples/config/TeamsLogger.json @@ -1,10 +1,7 @@ { - "DiscordBot": { - "Api key": "FNoqwinpqupqwuefbweufbAa.dFNWNO.nbpc29bSNiuib198172bp0987b1", - "Channel name": "teams-logger", - "Show server name in status": true - }, "Print logs to console": true, - "Print logs to Discord": true, - "Print logs to file": true + "Print logs to Discord": false, + "Print logs to file": true, + + "Discord hook url": null } \ No newline at end of file diff --git a/README.md b/README.md index b2fdc8e..5214a23 100644 --- a/README.md +++ b/README.md @@ -11,22 +11,15 @@ Then restart plugin using command in server console `oxide.reload TeamsLogger` ```JSON { "Print logs to console": true, - "Print logs to file": true, "Print logs to Discord": false, + "Print logs to file": true, - "DiscordBot": { - "Api key": null, - "Channel name": "teams-logger", - "Show server name in status": true - } + "Discord hook url": null } ``` -### Discord extension -To log messages into Discord, you'll need to install [Discord extension](https://umod.org/extensions/discord) and replace text `DISCORD_NOT_INSTALLED` by `DISCORD_INSTALLED` in the beginning of plugin file. - -### Discord Api key -To send messages, set `Api key` in configuration file. Instruction how to get this key you will find on [Discord extension page](https://umod.org/extensions/discord#getting-your-api-key). +### Discord +To send logs via Discord, you'll need to configure [Discord WebHook url](https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks). ## Localization ```JSON @@ -53,4 +46,4 @@ To file `\oxide\logs\TeamsLogger\teamslogger_common-####-##-##.txt` 17:36:26 Disband 97 | Team leader: 'xan' (76561198051734570) ``` ### To Discord -![](https://i.imgur.com/VohQkDJ.png) \ No newline at end of file +![](https://i.imgur.com/tlJiSXg.png) \ No newline at end of file diff --git a/TeamsLogger.cs b/TeamsLogger.cs index 7791930..bc92fe9 100644 --- a/TeamsLogger.cs +++ b/TeamsLogger.cs @@ -1,51 +1,32 @@ -#define DISCORD_NOT_INSTALLED - using Oxide.Core; using System; using System.Linq; +using UnityEngine; using System.Collections.Generic; using Newtonsoft.Json; - -#if DISCORD_INSTALLED -using Oxide.Ext.Discord; -using Oxide.Ext.Discord.Attributes; -using Oxide.Ext.Discord.DiscordObjects; -#endif +using System.Collections; +using System.Text; +using UnityEngine.Networking; namespace Oxide.Plugins { - [Info("Teams Logger", "NickRimmer", "1.3")] + [Info("Teams Logger", "NickRimmer", "1.4")] [Description("Simple plugin to log team events")] public class TeamsLogger : RustPlugin { - #if DISCORD_INSTALLED - [DiscordClient] - private DiscordClient _client; - private Channel _discordChannel; - #endif - private PluginConfig _config; + private DiscordComponent _discord; void Init() { _config = Config.ReadObject(); if (IsFirstRun()) LogCurrentTeams(); - } - - void OnServerInitialized() - { - #if DISCORD_INSTALLED - if (_config.PrintToDiscord) InitDiscord(); - #else - if (_config.PrintToDiscord) PrintWarning("To enable Discord features, please define DISCORD_INSTALLED directive"); - #endif - } - private void Unload() - { - #if DISCORD_INSTALLED - if (_client != null) Discord.CloseClient(_client); - #endif + if (!string.IsNullOrEmpty(_config.DiscordHookUrl)) + { + var loader = new GameObject("WebObject"); + _discord = loader.AddComponent().Configure(_config.DiscordHookUrl); + } } private void PrintToConsole(string message) => Puts(message); @@ -60,25 +41,16 @@ private void PrintToFile(string message) private void PrintToDiscord(string message) { - #if DISCORD_INSTALLED - if (_client?.DiscordServer == null) + if(_discord == null) { - PrintWarning("Discord doesn't connected"); - return; - } - - if (_discordChannel == null) - { - PrintWarning($"Discord channel with name '{_config.DiscordBot.ChannelName}' not found"); + PrintWarning("Discord wasn't configured, message can't be sent"); return; } var timestamp = DateTime.Now.ToString("HH:mm:ss"); message = $"{timestamp} | {message}"; - _discordChannel.CreateMessage(_client, message); - #else - PrintWarning("To enable discord features, please define DISCORD_INSTALLED directive"); - #endif + + _discord.SendTextMessage(message); } #region Log exist teams on first run @@ -119,51 +91,6 @@ private string GetUserInfo(ulong userId) } #endregion - #region Discord connection - #if DISCORD_INSTALLED - private void InitDiscord() - { - Puts("Init Discord connection..."); - if (string.IsNullOrEmpty(_config.DiscordBot.ApiKey)) - { - PrintError($"To enable Discord messages you need to specify 'DiscordConfig.ApiKey' value in config"); - return; - } - - Discord.CreateClient(this, _config.DiscordBot.ApiKey); - } - - void Discord_GuildCreate(Guild guild) - { - if(_config.DiscordBot.EnableBotStatus) - _client.UpdateStatus(new Presence { Game = new Ext.Discord.DiscordObjects.Game - { - Name = covalence.Server.Name, - Type = ActivityType.Watching - }}); - - UpdateDiscordChannel(); - } - - void Discord_ChannelCreate(Channel channel) => UpdateDiscordChannel(); - void Discord_ChannelUpdate(Channel updatedChannel, Channel oldChannel) => UpdateDiscordChannel(); - void Discord_ChannelDelete(Channel channel) => UpdateDiscordChannel(); - //void Discord_GuildUpdate(Guild guild) => UpdateDiscordChannel(); - - private void UpdateDiscordChannel() - { - _discordChannel = _client - .DiscordServer - .channels - .FirstOrDefault(x => x.name.Equals(_config.DiscordBot.ChannelName, StringComparison.InvariantCultureIgnoreCase)); - - if (_discordChannel == null) PrintWarning($"Discord channel with name '{_config.DiscordBot.ChannelName}' not found"); - else Puts($"Connected to discord channel: '{_discordChannel.name}' ({_discordChannel.id})"); - } - - #endif - #endregion - #region Team hooks void OnTeamInvite(BasePlayer inviter, BasePlayer target) => LogKey( @@ -302,26 +229,110 @@ private class PluginConfig [JsonProperty("Print logs to Discord")] public bool PrintToDiscord { get; set; } = false; - public PluginDiscordConfig DiscordBot = new PluginDiscordConfig(); + [JsonProperty("Discord hook url")] + public string DiscordHookUrl { get; set; } + } + + private class PluginData + { + public bool FirstStart { get; set; } = true; + } - public class PluginDiscordConfig + #endregion + + #region Shared.Components + + private class DiscordComponent : MonoBehaviour + { + private const float PostDelay = 1f; + + private readonly Queue _queue = new Queue(); + private string _url; + private bool _busy = false; + + public DiscordComponent Configure(string url) { - [JsonProperty("Api key")] - public string ApiKey { get; set; } + if (url == null) throw new ArgumentNullException(nameof(url)); + _url = url; - [JsonProperty("Channel name")] - public string ChannelName { get; set; } = "teams-logger"; + return this; + } - [JsonProperty("Show server name in status")] - public bool EnableBotStatus { get; set; } = true; + public DiscordComponent SendTextMessage(string message, params object[] args) + { + message = args?.Any() == true ? string.Format(message, args) : message; + return AddQueue(new MessageRequest(message)); } - } - private class PluginData - { - public bool FirstStart { get; set; } = true; + #region Send requests to server + + private DiscordComponent AddQueue(object request) + { + _queue.Enqueue(request); + + if (!_busy) + StartCoroutine(ProcessQueue()); + + return this; + } + + private IEnumerator ProcessQueue() + { + if(_busy) yield break; + _busy = true; + + while (_queue.Any()) + { + var request = _queue.Dequeue(); + yield return ProcessRequest(request); + } + + _busy = false; + } + + private IEnumerator ProcessRequest(object request) + { + if (string.IsNullOrEmpty(_url)) + { + print("[ERROR] Discord webhook URL wasn't specified"); + yield break; + } + + var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(request)); + var uh = new UploadHandlerRaw(data) {contentType = "application/json"}; + var www = UnityWebRequest.Post(_url, UnityWebRequest.kHttpVerbPOST); + www.uploadHandler = uh; + + yield return www.SendWebRequest(); + + if (www.isNetworkError || www.isHttpError) + print($"ERROR: {www.error} | {www.downloadHandler?.text}"); + + www.Dispose(); + + // to avoid spam requests to Discord + yield return new WaitForSeconds(PostDelay); + } + + #endregion + + #region Requests + + private class MessageRequest + { + [JsonProperty("content")] + public string Content { get; set; } + + public MessageRequest(string content) + { + if (content == null) throw new ArgumentNullException(nameof(content)); + Content = content; + } + } + + #endregion } #endregion } -} \ No newline at end of file +}