Skip to content

Commit db19732

Browse files
committed
Initial commit
0 parents  commit db19732

File tree

4 files changed

+278
-0
lines changed

4 files changed

+278
-0
lines changed

.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# JetBrains
2+
.idea/
3+
*.iml
4+
*.iws
5+
6+
# Visual Studio Code
7+
.vscode/
8+
.history
9+
10+
# Mac
11+
.DS_Store
12+
13+
# .NET
14+
libs/
15+
obj/

AzLink/AzLink.cs

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
using Newtonsoft.Json;
2+
using Oxide.Core.Libraries;
3+
using Oxide.Core.Libraries.Covalence;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
8+
namespace Oxide.Plugins;
9+
10+
[Info("AzLink", "Azuriom", AzLinkVersion)]
11+
[Description("Link your Azuriom website with an Oxide server.")]
12+
class AzLink : CovalencePlugin
13+
{
14+
private const string AzLinkVersion = "0.1.0";
15+
16+
private DateTime lastSent = DateTime.MinValue;
17+
private DateTime lastFullSent = DateTime.MinValue;
18+
19+
private void Init()
20+
{
21+
timer.Every(60, TryFetch);
22+
}
23+
24+
protected override void LoadDefaultConfig()
25+
{
26+
Log("Creating a new configuration file.");
27+
28+
Config["URL"] = null;
29+
Config["SiteKey"] = null;
30+
}
31+
32+
[Command("azlink.setup"), Permission("azlink.setup")]
33+
private void SetupCommand(IPlayer player, string command, string[] args)
34+
{
35+
if (args.Length < 2)
36+
{
37+
player.Reply(
38+
"You must first add this server in your Azuriom admin dashboard, in the 'Servers' section.");
39+
return;
40+
}
41+
42+
Config["URL"] = args[0];
43+
Config["SiteKey"] = args[1];
44+
45+
PingWebsite(() =>
46+
{
47+
player.Reply("Linked to the website successfully.");
48+
SaveConfig();
49+
}, code => player.Reply($"An error occurred, code {code}"));
50+
}
51+
52+
[Command("azlink.status"), Permission("azlink.status")]
53+
private void StatusCommand(IPlayer player, string command, string[] args)
54+
{
55+
if (Config["URL"] == null)
56+
{
57+
player.Reply("AzLink is not configured yet, use the 'setup' subcommand first.");
58+
return;
59+
}
60+
61+
PingWebsite(() => player.Reply("Connected to the website successfully."),
62+
code => player.Reply($"An error occurred, code {code}"));
63+
64+
player.Reply("Connected to the website successfully.");
65+
}
66+
67+
[Command("azlink.fetch"), Permission("azlink.fetch")]
68+
private void FetchCommand(IPlayer player, string command, string[] args)
69+
{
70+
if (Config["URL"] == null)
71+
{
72+
player.Reply("AzLink is not configured yet, use the 'setup' subcommand first.");
73+
return;
74+
}
75+
76+
RunFetch(res =>
77+
{
78+
DispatchCommands(res.Commands);
79+
80+
player.Reply("Data has been fetched successfully.");
81+
}, code => player.Reply($"An error occurred, code {code}"), true);
82+
}
83+
84+
private void TryFetch()
85+
{
86+
var url = (string?)Config["URL"];
87+
var siteKey = (string?)Config["SiteKey"];
88+
var now = DateTime.Now;
89+
90+
if (url == null || siteKey == null)
91+
{
92+
return;
93+
}
94+
95+
if ((now - lastSent).Seconds < 15)
96+
{
97+
return;
98+
}
99+
100+
lastSent = now;
101+
102+
var sendFull = now.Minute % 15 == 0 && (now - lastFullSent).Seconds > 60;
103+
104+
if (sendFull)
105+
{
106+
lastFullSent = now;
107+
}
108+
109+
RunFetch(res => DispatchCommands(res.Commands),
110+
code => LogError("Unable to send data to the website (code {0})", code), sendFull);
111+
}
112+
113+
private void RunFetch(Action<FetchResponse> callback, Action<int> errorHandler, bool sendFullData)
114+
{
115+
var url = (string)Config["URL"];
116+
var body = JsonConvert.SerializeObject(GetServerData(sendFullData));
117+
118+
webrequest.Enqueue($"{url}/api/azlink", body, (code, response) =>
119+
{
120+
if (code is < 200 or >= 300)
121+
{
122+
errorHandler(code);
123+
return;
124+
}
125+
126+
callback(JsonConvert.DeserializeObject<FetchResponse>(response));
127+
}, this, RequestMethod.POST, GetRequestHeaders());
128+
}
129+
130+
private void PingWebsite(Action onSuccess, Action<int> errorHandler)
131+
{
132+
var url = (string?)Config["URL"];
133+
var siteKey = (string?)Config["SiteKey"];
134+
135+
if (url == null || siteKey == null)
136+
{
137+
throw new ApplicationException("AzLink is not configured yet.");
138+
}
139+
140+
webrequest.Enqueue($"{url}/api/azlink", null, (code, _) =>
141+
{
142+
if (code is < 200 or >= 300)
143+
{
144+
errorHandler(code);
145+
return;
146+
}
147+
148+
onSuccess();
149+
}, this, RequestMethod.GET, GetRequestHeaders());
150+
}
151+
152+
private void DispatchCommands(ICollection<PendingCommand> commands)
153+
{
154+
if (commands.Count == 0)
155+
{
156+
return;
157+
}
158+
159+
foreach (var info in commands)
160+
{
161+
var player = players.FindPlayerById(info.UserId);
162+
var name = player?.Name ?? info.UserName;
163+
164+
foreach (var command in info.Values)
165+
{
166+
var cmd = command.Replace("{player}", name)
167+
.Replace("{steam_id}", info.UserId);
168+
169+
Log("Dispatching command to {0} ({1}): {2}", name, info.UserId, cmd);
170+
171+
server.Command(cmd);
172+
}
173+
}
174+
175+
Log("Dispatched commands to {0} players.", commands.Count);
176+
}
177+
178+
private Dictionary<string, object> GetServerData(bool includeFullData)
179+
{
180+
var online = players.Connected.Select(player => new Dictionary<string, string>
181+
{
182+
{ "name", player.Name }, { "uid", player.Id }
183+
});
184+
var data = new Dictionary<string, object>
185+
{
186+
{
187+
"platform", new Dictionary<string, string>()
188+
{
189+
{ "type", "OXIDE" },
190+
{ "name", $"Oxide - {game}" },
191+
{ "version", server.Version },
192+
}
193+
},
194+
{ "version", AzLinkVersion },
195+
{ "players", online },
196+
{ "maxPlayers", server.MaxPlayers },
197+
{ "full", includeFullData }
198+
};
199+
200+
if (includeFullData)
201+
{
202+
data.Add("ram", GC.GetTotalMemory(false) / 1024 / 1024);
203+
}
204+
205+
return data;
206+
}
207+
208+
private Dictionary<string, string> GetRequestHeaders()
209+
{
210+
return new Dictionary<string, string>
211+
{
212+
{ "Azuriom-Link-Token", (string)Config["SiteKey"] },
213+
{ "Accept", "application/json" },
214+
{ "Content-type", "application/json" },
215+
{ "User-Agent", "AzLink Oxide v" + AzLinkVersion },
216+
};
217+
}
218+
}
219+
220+
class FetchResponse
221+
{
222+
[JsonProperty("commands")] public List<PendingCommand> Commands { get; set; }
223+
}
224+
225+
class PendingCommand
226+
{
227+
[JsonProperty("uid")] public string UserId { get; set; }
228+
229+
[JsonProperty("name")] public string UserName { get; set; }
230+
231+
[JsonProperty("values")] public List<string> Values { get; set; }
232+
}

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Azuriom
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# AzLink-GMod
2+
3+
[![Latest release](https://img.shields.io/github/v/release/Azuriom/AzLink-Oxide?style=flat-square)](https://github.com/Azuriom/AzLink-Oxide/releases)
4+
[![Chat](https://img.shields.io/discord/625774284823986183?color=5865f2&label=Discord&logo=discord&logoColor=fff&style=flat-square)](https://azuriom.com/discord)
5+
6+
AzLink-Oxide is an [Oxide](https://umod.org/games) (uMod) plugin to link a Rust or 7 Days to Die server with Azuriom.
7+
8+
## Download
9+
10+
You can download the plugin on [Azuriom's website](https://azuriom.com/azlink) or in the [GitHub releases](https://github.com/Azuriom/AzLink-Oxide/releases).

0 commit comments

Comments
 (0)