Skip to content

Commit d69a698

Browse files
authored
Merge pull request #6 from rust-plugins/develop
Discord via webhooks
2 parents ec18735 + ac251ad commit d69a698

File tree

3 files changed

+121
-120
lines changed

3 files changed

+121
-120
lines changed

Examples/config/TeamsLogger.json

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
{
2-
"DiscordBot": {
3-
"Api key": "FNoqwinpqupqwuefbweufbAa.dFNWNO.nbpc29bSNiuib198172bp0987b1",
4-
"Channel name": "teams-logger",
5-
"Show server name in status": true
6-
},
72
"Print logs to console": true,
8-
"Print logs to Discord": true,
9-
"Print logs to file": true
3+
"Print logs to Discord": false,
4+
"Print logs to file": true,
5+
6+
"Discord hook url": null
107
}

README.md

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,15 @@ Then restart plugin using command in server console `oxide.reload TeamsLogger`
1111
```JSON
1212
{
1313
"Print logs to console": true,
14-
"Print logs to file": true,
1514
"Print logs to Discord": false,
15+
"Print logs to file": true,
1616

17-
"DiscordBot": {
18-
"Api key": null,
19-
"Channel name": "teams-logger",
20-
"Show server name in status": true
21-
}
17+
"Discord hook url": null
2218
}
2319
```
2420

25-
### Discord extension
26-
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.
27-
28-
### Discord Api key
29-
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).
21+
### Discord
22+
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).
3023

3124
## Localization
3225
```JSON
@@ -53,4 +46,4 @@ To file `\oxide\logs\TeamsLogger\teamslogger_common-####-##-##.txt`
5346
17:36:26 Disband 97 | Team leader: 'xan' (76561198051734570)
5447
```
5548
### To Discord
56-
![](https://i.imgur.com/VohQkDJ.png)
49+
![](https://i.imgur.com/tlJiSXg.png)

TeamsLogger.cs

Lines changed: 112 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,32 @@
1-
#define DISCORD_NOT_INSTALLED
2-
31
using Oxide.Core;
42
using System;
53
using System.Linq;
4+
using UnityEngine;
65
using System.Collections.Generic;
76
using Newtonsoft.Json;
8-
9-
#if DISCORD_INSTALLED
10-
using Oxide.Ext.Discord;
11-
using Oxide.Ext.Discord.Attributes;
12-
using Oxide.Ext.Discord.DiscordObjects;
13-
#endif
7+
using System.Collections;
8+
using System.Text;
9+
using UnityEngine.Networking;
1410

1511
namespace Oxide.Plugins
1612
{
17-
[Info("Teams Logger", "NickRimmer", "1.3")]
13+
[Info("Teams Logger", "NickRimmer", "1.4")]
1814
[Description("Simple plugin to log team events")]
1915
public class TeamsLogger : RustPlugin
2016
{
21-
#if DISCORD_INSTALLED
22-
[DiscordClient]
23-
private DiscordClient _client;
24-
private Channel _discordChannel;
25-
#endif
26-
2717
private PluginConfig _config;
18+
private DiscordComponent _discord;
2819

2920
void Init()
3021
{
3122
_config = Config.ReadObject<PluginConfig>();
3223
if (IsFirstRun()) LogCurrentTeams();
33-
}
34-
35-
void OnServerInitialized()
36-
{
37-
#if DISCORD_INSTALLED
38-
if (_config.PrintToDiscord) InitDiscord();
39-
#else
40-
if (_config.PrintToDiscord) PrintWarning("To enable Discord features, please define DISCORD_INSTALLED directive");
41-
#endif
42-
}
4324

44-
private void Unload()
45-
{
46-
#if DISCORD_INSTALLED
47-
if (_client != null) Discord.CloseClient(_client);
48-
#endif
25+
if (!string.IsNullOrEmpty(_config.DiscordHookUrl))
26+
{
27+
var loader = new GameObject("WebObject");
28+
_discord = loader.AddComponent<DiscordComponent>().Configure(_config.DiscordHookUrl);
29+
}
4930
}
5031

5132
private void PrintToConsole(string message) => Puts(message);
@@ -60,25 +41,16 @@ private void PrintToFile(string message)
6041

6142
private void PrintToDiscord(string message)
6243
{
63-
#if DISCORD_INSTALLED
64-
if (_client?.DiscordServer == null)
44+
if(_discord == null)
6545
{
66-
PrintWarning("Discord doesn't connected");
67-
return;
68-
}
69-
70-
if (_discordChannel == null)
71-
{
72-
PrintWarning($"Discord channel with name '{_config.DiscordBot.ChannelName}' not found");
46+
PrintWarning("Discord wasn't configured, message can't be sent");
7347
return;
7448
}
7549

7650
var timestamp = DateTime.Now.ToString("HH:mm:ss");
7751
message = $"{timestamp} | {message}";
78-
_discordChannel.CreateMessage(_client, message);
79-
#else
80-
PrintWarning("To enable discord features, please define DISCORD_INSTALLED directive");
81-
#endif
52+
53+
_discord.SendTextMessage(message);
8254
}
8355

8456
#region Log exist teams on first run
@@ -119,51 +91,6 @@ private string GetUserInfo(ulong userId)
11991
}
12092
#endregion
12193

122-
#region Discord connection
123-
#if DISCORD_INSTALLED
124-
private void InitDiscord()
125-
{
126-
Puts("Init Discord connection...");
127-
if (string.IsNullOrEmpty(_config.DiscordBot.ApiKey))
128-
{
129-
PrintError($"To enable Discord messages you need to specify 'DiscordConfig.ApiKey' value in config");
130-
return;
131-
}
132-
133-
Discord.CreateClient(this, _config.DiscordBot.ApiKey);
134-
}
135-
136-
void Discord_GuildCreate(Guild guild)
137-
{
138-
if(_config.DiscordBot.EnableBotStatus)
139-
_client.UpdateStatus(new Presence { Game = new Ext.Discord.DiscordObjects.Game
140-
{
141-
Name = covalence.Server.Name,
142-
Type = ActivityType.Watching
143-
}});
144-
145-
UpdateDiscordChannel();
146-
}
147-
148-
void Discord_ChannelCreate(Channel channel) => UpdateDiscordChannel();
149-
void Discord_ChannelUpdate(Channel updatedChannel, Channel oldChannel) => UpdateDiscordChannel();
150-
void Discord_ChannelDelete(Channel channel) => UpdateDiscordChannel();
151-
//void Discord_GuildUpdate(Guild guild) => UpdateDiscordChannel();
152-
153-
private void UpdateDiscordChannel()
154-
{
155-
_discordChannel = _client
156-
.DiscordServer
157-
.channels
158-
.FirstOrDefault(x => x.name.Equals(_config.DiscordBot.ChannelName, StringComparison.InvariantCultureIgnoreCase));
159-
160-
if (_discordChannel == null) PrintWarning($"Discord channel with name '{_config.DiscordBot.ChannelName}' not found");
161-
else Puts($"Connected to discord channel: '{_discordChannel.name}' ({_discordChannel.id})");
162-
}
163-
164-
#endif
165-
#endregion
166-
16794
#region Team hooks
16895

16996
void OnTeamInvite(BasePlayer inviter, BasePlayer target) => LogKey(
@@ -302,26 +229,110 @@ private class PluginConfig
302229
[JsonProperty("Print logs to Discord")]
303230
public bool PrintToDiscord { get; set; } = false;
304231

305-
public PluginDiscordConfig DiscordBot = new PluginDiscordConfig();
232+
[JsonProperty("Discord hook url")]
233+
public string DiscordHookUrl { get; set; }
234+
}
235+
236+
private class PluginData
237+
{
238+
public bool FirstStart { get; set; } = true;
239+
}
306240

307-
public class PluginDiscordConfig
241+
#endregion
242+
243+
#region Shared.Components
244+
245+
private class DiscordComponent : MonoBehaviour
246+
{
247+
private const float PostDelay = 1f;
248+
249+
private readonly Queue<object> _queue = new Queue<object>();
250+
private string _url;
251+
private bool _busy = false;
252+
253+
public DiscordComponent Configure(string url)
308254
{
309-
[JsonProperty("Api key")]
310-
public string ApiKey { get; set; }
255+
if (url == null) throw new ArgumentNullException(nameof(url));
256+
_url = url;
311257

312-
[JsonProperty("Channel name")]
313-
public string ChannelName { get; set; } = "teams-logger";
258+
return this;
259+
}
314260

315-
[JsonProperty("Show server name in status")]
316-
public bool EnableBotStatus { get; set; } = true;
261+
public DiscordComponent SendTextMessage(string message, params object[] args)
262+
{
263+
message = args?.Any() == true ? string.Format(message, args) : message;
264+
return AddQueue(new MessageRequest(message));
317265
}
318-
}
319266

320-
private class PluginData
321-
{
322-
public bool FirstStart { get; set; } = true;
267+
#region Send requests to server
268+
269+
private DiscordComponent AddQueue(object request)
270+
{
271+
_queue.Enqueue(request);
272+
273+
if (!_busy)
274+
StartCoroutine(ProcessQueue());
275+
276+
return this;
277+
}
278+
279+
private IEnumerator ProcessQueue()
280+
{
281+
if(_busy) yield break;
282+
_busy = true;
283+
284+
while (_queue.Any())
285+
{
286+
var request = _queue.Dequeue();
287+
yield return ProcessRequest(request);
288+
}
289+
290+
_busy = false;
291+
}
292+
293+
private IEnumerator ProcessRequest(object request)
294+
{
295+
if (string.IsNullOrEmpty(_url))
296+
{
297+
print("[ERROR] Discord webhook URL wasn't specified");
298+
yield break;
299+
}
300+
301+
var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(request));
302+
var uh = new UploadHandlerRaw(data) {contentType = "application/json"};
303+
var www = UnityWebRequest.Post(_url, UnityWebRequest.kHttpVerbPOST);
304+
www.uploadHandler = uh;
305+
306+
yield return www.SendWebRequest();
307+
308+
if (www.isNetworkError || www.isHttpError)
309+
print($"ERROR: {www.error} | {www.downloadHandler?.text}");
310+
311+
www.Dispose();
312+
313+
// to avoid spam requests to Discord
314+
yield return new WaitForSeconds(PostDelay);
315+
}
316+
317+
#endregion
318+
319+
#region Requests
320+
321+
private class MessageRequest
322+
{
323+
[JsonProperty("content")]
324+
public string Content { get; set; }
325+
326+
public MessageRequest(string content)
327+
{
328+
if (content == null) throw new ArgumentNullException(nameof(content));
329+
Content = content;
330+
}
331+
}
332+
333+
#endregion
323334
}
324335

325336
#endregion
326337
}
327-
}
338+
}

0 commit comments

Comments
 (0)