Compare commits
306 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f48ec2245c | ||
|
|
37a3a35120 | ||
|
|
c549d45d54 | ||
|
|
42a011541c | ||
|
|
71a8839f5f | ||
|
|
b99e8b5476 | ||
|
|
5793bd9747 | ||
|
|
24ce51a62e | ||
|
|
762d3cc1a1 | ||
|
|
ea19105006 | ||
|
|
a372c756e4 | ||
|
|
18b7c82613 | ||
|
|
5d91077d42 | ||
|
|
c0872d0d02 | ||
|
|
00722c4046 | ||
|
|
f16a29dafb | ||
|
|
6da8393612 | ||
|
|
2ef00b81b8 | ||
|
|
0be4ebc7ff | ||
|
|
e0d5e754b7 | ||
|
|
6972c2bb32 | ||
|
|
95ba81eab4 | ||
|
|
b9c094cafa | ||
|
|
bada1e829b | ||
|
|
1d33cf3110 | ||
|
|
abfcefba60 | ||
|
|
6efb443481 | ||
|
|
10c017932a | ||
|
|
a4be4bdc52 | ||
|
|
88d5a1de86 | ||
|
|
1b88827d16 | ||
|
|
12e25dc4bc | ||
|
|
37c3fc7a53 | ||
|
|
0c6cbe0ba7 | ||
|
|
5cf63240a3 | ||
|
|
4d04d12a39 | ||
|
|
b846b28802 | ||
|
|
b94217abc0 | ||
|
|
de0d6a3808 | ||
|
|
eca9b6ec52 | ||
|
|
b6e048e982 | ||
|
|
b8b2ae7865 | ||
|
|
0611988019 | ||
|
|
f9fd7199b6 | ||
|
|
6ff4861fc6 | ||
|
|
2db7748703 | ||
|
|
87744e4846 | ||
|
|
ce7125b50b | ||
|
|
31d8c3f469 | ||
|
|
c80622c2fd | ||
|
|
95e659e5f7 | ||
|
|
c155909e82 | ||
|
|
0011ed29b7 | ||
|
|
52c4ca0c0a | ||
|
|
c197d0ca96 | ||
|
|
25902034e9 | ||
|
|
b10db643fe | ||
|
|
4c7ffe6714 | ||
|
|
a0c2b45a61 | ||
|
|
e49a9d3505 | ||
|
|
7ddae9c3e1 | ||
|
|
290e865ae0 | ||
|
|
00ee625e2e | ||
|
|
274e2d93f2 | ||
|
|
781171f7c5 | ||
|
|
4a8618da79 | ||
|
|
296cf0db6f | ||
|
|
48cdba5155 | ||
|
|
35c1b255b5 | ||
|
|
244b920305 | ||
|
|
3d4a2128e2 | ||
|
|
1cf8430ad8 | ||
|
|
a9b7d10fb0 | ||
|
|
47e333630e | ||
|
|
8b41a9fc13 | ||
|
|
d09957fdac | ||
|
|
f9ecb61d71 | ||
|
|
ef92dd47ad | ||
|
|
c2c533675b | ||
|
|
569dd69bdd | ||
|
|
242870b3e1 | ||
|
|
30b6e45235 | ||
|
|
cd62fdc5f6 | ||
|
|
2c54b91e6c | ||
|
|
388deacf60 | ||
|
|
aa547038de | ||
|
|
78bfd68d63 | ||
|
|
17e3345b8a | ||
|
|
f95312c1e3 | ||
|
|
2144ca3823 | ||
|
|
de45ff40d8 | ||
|
|
606085c012 | ||
|
|
00525d8099 | ||
|
|
26617d67f5 | ||
|
|
600bec3417 | ||
|
|
4e85d1755a | ||
|
|
0832936933 | ||
|
|
ecda2ec6d1 | ||
|
|
6f3765a3bf | ||
|
|
29002d3445 | ||
|
|
6d0456a008 | ||
|
|
3e698123bb | ||
|
|
f3fb86819a | ||
|
|
e2248a8444 | ||
|
|
2cf2b77090 | ||
|
|
fedc9278d4 | ||
|
|
f29206a69b | ||
|
|
0658e55a78 | ||
|
|
21bea974a9 | ||
|
|
33ef09433e | ||
|
|
173bff67df | ||
|
|
512a989609 | ||
|
|
2d7dac5089 | ||
|
|
11708fbc3b | ||
|
|
daeb4dd5b9 | ||
|
|
daba4cba04 | ||
|
|
1cd0f0f96f | ||
|
|
6a30db07a7 | ||
|
|
6c8754d008 | ||
|
|
356ba94592 | ||
|
|
d3b55d155b | ||
|
|
0015001d7c | ||
|
|
0a86aa8aa4 | ||
|
|
74d4ee729d | ||
|
|
178ff36e86 | ||
|
|
f852df5807 | ||
|
|
90f4b04857 | ||
|
|
244e87ed18 | ||
|
|
80ea5a543f | ||
|
|
5baba05f5f | ||
|
|
591da6de5c | ||
|
|
c1ddff4ae3 | ||
|
|
67d78d7104 | ||
|
|
52f4b00f84 | ||
|
|
8f028e2ac6 | ||
|
|
5bd6f15203 | ||
|
|
4c39ad6170 | ||
|
|
12392d4f47 | ||
|
|
b75147e4c0 | ||
|
|
8f9508f30b | ||
|
|
428e2668d3 | ||
|
|
c1cfb35c86 | ||
|
|
d6777c463e | ||
|
|
f9126bffe0 | ||
|
|
0488e83a38 | ||
|
|
d87ddc90e3 | ||
|
|
151bc82998 | ||
|
|
e4c21c74a5 | ||
|
|
13741a2be9 | ||
|
|
c866e89b72 | ||
|
|
8be93bc53c | ||
|
|
384b6a3e7d | ||
|
|
ba2de54c60 | ||
|
|
bd5567e24f | ||
|
|
b8e39824b5 | ||
|
|
d8c9bdbd8d | ||
|
|
80eb210af0 | ||
|
|
a295354549 | ||
|
|
749ea5dc8e | ||
|
|
f52b9e2951 | ||
|
|
d2dbb68967 | ||
|
|
d1c9009e9f | ||
|
|
d024a834f9 | ||
|
|
c0df8ac507 | ||
|
|
ab529991fd | ||
|
|
92705837ba | ||
|
|
609d5451f9 | ||
|
|
2bb2caeeed | ||
|
|
61db49bfb7 | ||
|
|
a75678d305 | ||
|
|
d418c91efa | ||
|
|
7f2da5a55d | ||
|
|
5e592ccdcb | ||
|
|
016f50fb1c | ||
|
|
fe21668a2b | ||
|
|
1aab86a317 | ||
|
|
243d23d4e2 | ||
|
|
2fe17473ae | ||
|
|
609cf8cfac | ||
|
|
678da30b09 | ||
|
|
d19412f4bb | ||
|
|
1665d6e537 | ||
|
|
fd210f2404 | ||
|
|
c33729fb44 | ||
|
|
7983bf3ee4 | ||
|
|
a09f60aea7 | ||
|
|
28b5893c21 | ||
|
|
25b47d8b6c | ||
|
|
85f5b8a7da | ||
|
|
ab9333f99a | ||
|
|
d60f8fc905 | ||
|
|
fe1f4412d8 | ||
|
|
f191533410 | ||
|
|
a894707536 | ||
|
|
d2ccc84286 | ||
|
|
f2ec43f2d2 | ||
|
|
7feccc8d9f | ||
|
|
a8bd1193ce | ||
|
|
366d1a9205 | ||
|
|
df9ed95c6b | ||
|
|
23a211362e | ||
|
|
cf91d44902 | ||
|
|
35633e21a9 | ||
|
|
ce8b8f6798 | ||
|
|
c28c80ba25 | ||
|
|
da17b1df93 | ||
|
|
f9f5865ef9 | ||
|
|
389ded9b77 | ||
|
|
faebaa59dd | ||
|
|
6b7dc2ad05 | ||
|
|
e356c9d0c8 | ||
|
|
efed2a6a5c | ||
|
|
6f138c2c51 | ||
|
|
6c43e6a533 | ||
|
|
0379afd831 | ||
|
|
b8bfdb7729 | ||
|
|
72f60ec97c | ||
|
|
1b40250750 | ||
|
|
cdf2988cb6 | ||
|
|
76415b4a0a | ||
|
|
52d00baf2b | ||
|
|
cd41db510e | ||
|
|
1afd4e8b92 | ||
|
|
ef37088c7a | ||
|
|
e71495533b | ||
|
|
e2a6d70f6a | ||
|
|
e95853b09c | ||
|
|
0537ca115e | ||
|
|
432e441972 | ||
|
|
1dae5150bd | ||
|
|
72c6f636ee | ||
|
|
e54d04277d | ||
|
|
f559f08e8d | ||
|
|
2674fb3fa7 | ||
|
|
d5d77ae7da | ||
|
|
3ae905038c | ||
|
|
6707d722e0 | ||
|
|
bc9fecf6d9 | ||
|
|
c2cb10f069 | ||
|
|
cc06d1eb0b | ||
|
|
916ff71022 | ||
|
|
9e80342e26 | ||
|
|
0fb97683bf | ||
|
|
32415bad54 | ||
|
|
d2b0bcc4a3 | ||
|
|
2f4f4193d3 | ||
|
|
7279f05a16 | ||
|
|
3962723acb | ||
|
|
125e72fa58 | ||
|
|
880cce060f | ||
|
|
0e04942111 | ||
|
|
46a88d4638 | ||
|
|
c7c39fc511 | ||
|
|
3b9bdd1916 | ||
|
|
d267be6d69 | ||
|
|
18f6a1acdc | ||
|
|
2ca41ff18f | ||
|
|
74c77bc744 | ||
|
|
1ff8cdd7a9 | ||
|
|
bd320d025a | ||
|
|
9a5b004e17 | ||
|
|
3aee059860 | ||
|
|
3dfa7f66de | ||
|
|
c2949b4773 | ||
|
|
c2d0ab4b1b | ||
|
|
de02f0bd74 | ||
|
|
e280a95619 | ||
|
|
6f06be9cc6 | ||
|
|
08745a83b4 | ||
|
|
9a262d1396 | ||
|
|
0a1b93b8fb | ||
|
|
4b638fc5da | ||
|
|
d8e34ae891 | ||
|
|
311237e49d | ||
|
|
6591bbc927 | ||
|
|
43c5717d19 | ||
|
|
61d547b2ce | ||
|
|
d7fbe54225 | ||
|
|
d0004e9fff | ||
|
|
829596a3e7 | ||
|
|
fc319f0f73 | ||
|
|
bd8ba11410 | ||
|
|
0c4fc942b0 | ||
|
|
94b8f07d92 | ||
|
|
f11eef2734 | ||
|
|
0f8946fe27 | ||
|
|
a8cb1392e8 | ||
|
|
4241debc3b | ||
|
|
a99959bd2b | ||
|
|
23644eb93f | ||
|
|
f8fcb86ad8 | ||
|
|
ce0016fa3f | ||
|
|
15d8f49ce9 | ||
|
|
98d8e5b755 | ||
|
|
bfa1a09aab | ||
|
|
84396c34e6 | ||
|
|
4fb4a2415b | ||
|
|
c6cf11626e | ||
|
|
233c304b3c | ||
|
|
343e527fb6 | ||
|
|
25da3c233e | ||
|
|
d7fb3382f7 | ||
|
|
88c9f5372d | ||
|
|
7128a7f8a7 | ||
| 0fde9a5005 | |||
|
|
74541d7f87 |
8
.gitattributes
vendored
8
.gitattributes
vendored
@@ -1,2 +1,10 @@
|
|||||||
# Auto detect text files and perform LF normalization
|
# Auto detect text files and perform LF normalization
|
||||||
* text=auto
|
* text=auto
|
||||||
|
Moonlight/wwwroot/** linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/js/scripts.bundle.js linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/js/widgets.bundle.js linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/js/theme.js linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/css/boxicons.min.css linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/css/style.bundle.css linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/plugins/** linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/fonts/** linguist-vendored
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -42,3 +42,4 @@ Desktop.ini
|
|||||||
|
|
||||||
storage/
|
storage/
|
||||||
Moonlight/publish.ps1
|
Moonlight/publish.ps1
|
||||||
|
Moonlight/version
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Moonlight.App.Database.Entities;
|
using Moonlight.App.Database.Entities;
|
||||||
using Moonlight.App.Exceptions;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
|
|
||||||
@@ -14,26 +13,13 @@ public class DaemonApiHelper
|
|||||||
Client = new();
|
Client = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetApiUrl(Node node)
|
|
||||||
{
|
|
||||||
/* SSL not implemented in moonlight daemon
|
|
||||||
if(node.Ssl)
|
|
||||||
return $"https://{node.Fqdn}:{node.MoonlightDaemonPort}/";
|
|
||||||
else
|
|
||||||
return $"http://{node.Fqdn}:{node.MoonlightDaemonPort}/";*/
|
|
||||||
|
|
||||||
return $"http://{node.Fqdn}:{node.MoonlightDaemonPort}/";
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<T> Get<T>(Node node, string resource)
|
public async Task<T> Get<T>(Node node, string resource)
|
||||||
{
|
{
|
||||||
RestRequest request = new(GetApiUrl(node) + resource);
|
var request = await CreateRequest(node, resource);
|
||||||
|
|
||||||
request.AddHeader("Content-Type", "application/json");
|
request.Method = Method.Get;
|
||||||
request.AddHeader("Accept", "application/json");
|
|
||||||
request.AddHeader("Authorization", node.Token);
|
var response = await Client.ExecuteAsync(request);
|
||||||
|
|
||||||
var response = await Client.GetAsync(request);
|
|
||||||
|
|
||||||
if (!response.IsSuccessful)
|
if (!response.IsSuccessful)
|
||||||
{
|
{
|
||||||
@@ -52,4 +38,69 @@ public class DaemonApiHelper
|
|||||||
|
|
||||||
return JsonConvert.DeserializeObject<T>(response.Content!)!;
|
return JsonConvert.DeserializeObject<T>(response.Content!)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task Post(Node node, string resource, object body)
|
||||||
|
{
|
||||||
|
var request = await CreateRequest(node, resource);
|
||||||
|
|
||||||
|
request.Method = Method.Post;
|
||||||
|
|
||||||
|
request.AddParameter("text/plain", JsonConvert.SerializeObject(body), ParameterType.RequestBody);
|
||||||
|
|
||||||
|
var response = await Client.ExecuteAsync(request);
|
||||||
|
|
||||||
|
if (!response.IsSuccessful)
|
||||||
|
{
|
||||||
|
if (response.StatusCode != 0)
|
||||||
|
{
|
||||||
|
throw new DaemonException(
|
||||||
|
$"An error occured: ({response.StatusCode}) {response.Content}",
|
||||||
|
(int)response.StatusCode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"An internal error occured: {response.ErrorMessage}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Delete(Node node, string resource, object body)
|
||||||
|
{
|
||||||
|
var request = await CreateRequest(node, resource);
|
||||||
|
|
||||||
|
request.Method = Method.Delete;
|
||||||
|
|
||||||
|
request.AddParameter("text/plain", JsonConvert.SerializeObject(body), ParameterType.RequestBody);
|
||||||
|
|
||||||
|
var response = await Client.ExecuteAsync(request);
|
||||||
|
|
||||||
|
if (!response.IsSuccessful)
|
||||||
|
{
|
||||||
|
if (response.StatusCode != 0)
|
||||||
|
{
|
||||||
|
throw new DaemonException(
|
||||||
|
$"An error occured: ({response.StatusCode}) {response.Content}",
|
||||||
|
(int)response.StatusCode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"An internal error occured: {response.ErrorMessage}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task<RestRequest> CreateRequest(Node node, string resource)
|
||||||
|
{
|
||||||
|
var url = $"http://{node.Fqdn}:{node.MoonlightDaemonPort}/";
|
||||||
|
|
||||||
|
RestRequest request = new(url + resource);
|
||||||
|
|
||||||
|
request.AddHeader("Content-Type", "application/json");
|
||||||
|
request.AddHeader("Accept", "application/json");
|
||||||
|
request.AddHeader("Authorization", node.Token);
|
||||||
|
|
||||||
|
return Task.FromResult(request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
8
Moonlight/App/ApiClients/Daemon/Requests/Mount.cs
Normal file
8
Moonlight/App/ApiClients/Daemon/Requests/Mount.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Moonlight.App.ApiClients.Daemon.Requests;
|
||||||
|
|
||||||
|
public class Mount
|
||||||
|
{
|
||||||
|
public string Server { get; set; } = "";
|
||||||
|
public string ServerPath { get; set; } = "";
|
||||||
|
public string Path { get; set; } = "";
|
||||||
|
}
|
||||||
6
Moonlight/App/ApiClients/Daemon/Requests/Unmount.cs
Normal file
6
Moonlight/App/ApiClients/Daemon/Requests/Unmount.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Moonlight.App.ApiClients.Daemon.Requests;
|
||||||
|
|
||||||
|
public class Unmount
|
||||||
|
{
|
||||||
|
public string Path { get; set; } = "";
|
||||||
|
}
|
||||||
10
Moonlight/App/ApiClients/Daemon/Resources/Container.cs
Normal file
10
Moonlight/App/ApiClients/Daemon/Resources/Container.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Moonlight.App.ApiClients.Daemon.Resources;
|
||||||
|
|
||||||
|
public class Container
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public long Memory { get; set; }
|
||||||
|
public double Cpu { get; set; }
|
||||||
|
public long NetworkIn { get; set; }
|
||||||
|
public long NetworkOut { get; set; }
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
namespace Moonlight.App.ApiClients.Daemon.Resources;
|
|
||||||
|
|
||||||
public class ContainerStats
|
|
||||||
{
|
|
||||||
public List<Container> Containers { get; set; } = new();
|
|
||||||
|
|
||||||
public class Container
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public long Memory { get; set; }
|
|
||||||
public double Cpu { get; set; }
|
|
||||||
public long NetworkIn { get; set; }
|
|
||||||
public long NetworkOut { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
7
Moonlight/App/ApiClients/Daemon/Resources/CpuMetrics.cs
Normal file
7
Moonlight/App/ApiClients/Daemon/Resources/CpuMetrics.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Moonlight.App.ApiClients.Daemon.Resources;
|
||||||
|
|
||||||
|
public class CpuMetrics
|
||||||
|
{
|
||||||
|
public string CpuModel { get; set; } = "";
|
||||||
|
public double CpuUsage { get; set; }
|
||||||
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace Moonlight.App.ApiClients.Daemon.Resources;
|
|
||||||
|
|
||||||
public class CpuStats
|
|
||||||
{
|
|
||||||
public double Usage { get; set; }
|
|
||||||
public int Cores { get; set; }
|
|
||||||
public string Model { get; set; } = "";
|
|
||||||
}
|
|
||||||
7
Moonlight/App/ApiClients/Daemon/Resources/DiskMetrics.cs
Normal file
7
Moonlight/App/ApiClients/Daemon/Resources/DiskMetrics.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Moonlight.App.ApiClients.Daemon.Resources;
|
||||||
|
|
||||||
|
public class DiskMetrics
|
||||||
|
{
|
||||||
|
public long Used { get; set; }
|
||||||
|
public long Total { get; set; }
|
||||||
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Moonlight.App.ApiClients.Daemon.Resources;
|
|
||||||
|
|
||||||
public class DiskStats
|
|
||||||
{
|
|
||||||
public long FreeBytes { get; set; }
|
|
||||||
public string DriveFormat { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public long TotalSize { get; set; }
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Moonlight.App.ApiClients.Daemon.Resources;
|
||||||
|
|
||||||
|
public class DockerMetrics
|
||||||
|
{
|
||||||
|
public Container[] Containers { get; set; } = Array.Empty<Container>();
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Moonlight.App.ApiClients.Daemon.Resources;
|
||||||
|
|
||||||
|
public class MemoryMetrics
|
||||||
|
{
|
||||||
|
public long Used { get; set; }
|
||||||
|
public long Total { get; set; }
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
namespace Moonlight.App.ApiClients.Daemon.Resources;
|
|
||||||
|
|
||||||
public class MemoryStats
|
|
||||||
{
|
|
||||||
public List<MemoryStick> Sticks { get; set; } = new();
|
|
||||||
public double Free { get; set; }
|
|
||||||
public double Used { get; set; }
|
|
||||||
public double Total { get; set; }
|
|
||||||
|
|
||||||
public class MemoryStick
|
|
||||||
{
|
|
||||||
public int Size { get; set; }
|
|
||||||
public string Type { get; set; } = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Moonlight.App.ApiClients.Daemon.Resources;
|
||||||
|
|
||||||
|
public class SystemMetrics
|
||||||
|
{
|
||||||
|
public string OsName { get; set; } = "";
|
||||||
|
public long Uptime { get; set; }
|
||||||
|
}
|
||||||
58
Moonlight/App/ApiClients/Modrinth/ModrinthApiHelper.cs
Normal file
58
Moonlight/App/ApiClients/Modrinth/ModrinthApiHelper.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using RestSharp;
|
||||||
|
|
||||||
|
namespace Moonlight.App.ApiClients.Modrinth;
|
||||||
|
|
||||||
|
public class ModrinthApiHelper
|
||||||
|
{
|
||||||
|
private readonly RestClient Client;
|
||||||
|
|
||||||
|
public ModrinthApiHelper()
|
||||||
|
{
|
||||||
|
Client = new();
|
||||||
|
Client.AddDefaultParameter(
|
||||||
|
new HeaderParameter("User-Agent", "Moonlight-Panel/Moonlight (admin@endelon-hosting.de)")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<T> Get<T>(string resource)
|
||||||
|
{
|
||||||
|
var request = CreateRequest(resource);
|
||||||
|
|
||||||
|
request.Method = Method.Get;
|
||||||
|
|
||||||
|
var response = await Client.ExecuteAsync(request);
|
||||||
|
|
||||||
|
if (!response.IsSuccessful)
|
||||||
|
{
|
||||||
|
if (response.StatusCode != 0)
|
||||||
|
{
|
||||||
|
throw new ModrinthException(
|
||||||
|
$"An error occured: ({response.StatusCode}) {response.Content}",
|
||||||
|
(int)response.StatusCode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"An internal error occured: {response.ErrorMessage}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonConvert.DeserializeObject<T>(response.Content!)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestRequest CreateRequest(string resource)
|
||||||
|
{
|
||||||
|
var url = "https://api.modrinth.com/v2/" + resource;
|
||||||
|
|
||||||
|
var request = new RestRequest(url)
|
||||||
|
{
|
||||||
|
Timeout = 300000
|
||||||
|
};
|
||||||
|
|
||||||
|
request.AddHeader("Content-Type", "application/json");
|
||||||
|
request.AddHeader("Accept", "application/json");
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Moonlight/App/ApiClients/Modrinth/ModrinthException.cs
Normal file
19
Moonlight/App/ApiClients/Modrinth/ModrinthException.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
namespace Moonlight.App.ApiClients.Modrinth;
|
||||||
|
|
||||||
|
public class ModrinthException : Exception
|
||||||
|
{
|
||||||
|
public int StatusCode { get; set; }
|
||||||
|
|
||||||
|
public ModrinthException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModrinthException(string message, int statusCode) : base(message)
|
||||||
|
{
|
||||||
|
StatusCode = statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModrinthException(string message, Exception inner) : base(message, inner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
14
Moonlight/App/ApiClients/Modrinth/Resources/Pagination.cs
Normal file
14
Moonlight/App/ApiClients/Modrinth/Resources/Pagination.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Moonlight.App.ApiClients.Modrinth.Resources;
|
||||||
|
|
||||||
|
public class Pagination
|
||||||
|
{
|
||||||
|
[JsonProperty("hits")] public Project[] Hits { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("offset")] public long Offset { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("limit")] public long Limit { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("total_hits")] public long TotalHits { get; set; }
|
||||||
|
}
|
||||||
48
Moonlight/App/ApiClients/Modrinth/Resources/Project.cs
Normal file
48
Moonlight/App/ApiClients/Modrinth/Resources/Project.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Moonlight.App.ApiClients.Modrinth.Resources;
|
||||||
|
|
||||||
|
public class Project
|
||||||
|
{
|
||||||
|
[JsonProperty("project_id")] public string ProjectId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("project_type")] public string ProjectType { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("slug")] public string Slug { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("author")] public string Author { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("title")] public string Title { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("description")] public string Description { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("categories")] public string[] Categories { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("display_categories")] public string[] DisplayCategories { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("versions")] public string[] Versions { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("downloads")] public long Downloads { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("follows")] public long Follows { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("icon_url")] public string IconUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("date_created")] public DateTimeOffset DateCreated { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("date_modified")] public DateTimeOffset DateModified { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("latest_version")] public string LatestVersion { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("license")] public string License { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("client_side")] public string ClientSide { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("server_side")] public string ServerSide { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("gallery")] public Uri[] Gallery { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("featured_gallery")] public Uri FeaturedGallery { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("color")] public long? Color { get; set; }
|
||||||
|
}
|
||||||
57
Moonlight/App/ApiClients/Modrinth/Resources/Version.cs
Normal file
57
Moonlight/App/ApiClients/Modrinth/Resources/Version.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Moonlight.App.ApiClients.Modrinth.Resources;
|
||||||
|
|
||||||
|
public class Version
|
||||||
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("version_number")]
|
||||||
|
public string VersionNumber { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("changelog")]
|
||||||
|
public string Changelog { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("dependencies")]
|
||||||
|
public object[] Dependencies { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("game_versions")]
|
||||||
|
public object[] GameVersions { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("version_type")]
|
||||||
|
public string VersionType { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("loaders")]
|
||||||
|
public object[] Loaders { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("featured")]
|
||||||
|
public bool Featured { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("status")]
|
||||||
|
public string Status { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("requested_status")]
|
||||||
|
public string RequestedStatus { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("project_id")]
|
||||||
|
public string ProjectId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("author_id")]
|
||||||
|
public string AuthorId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("date_published")]
|
||||||
|
public DateTime DatePublished { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("downloads")]
|
||||||
|
public long Downloads { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("changelog_url")]
|
||||||
|
public object ChangelogUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("files")]
|
||||||
|
public VersionFile[] Files { get; set; }
|
||||||
|
}
|
||||||
21
Moonlight/App/ApiClients/Modrinth/Resources/VersionFile.cs
Normal file
21
Moonlight/App/ApiClients/Modrinth/Resources/VersionFile.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Moonlight.App.ApiClients.Modrinth.Resources;
|
||||||
|
|
||||||
|
public class VersionFile
|
||||||
|
{
|
||||||
|
[JsonProperty("url")]
|
||||||
|
public Uri Url { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("filename")]
|
||||||
|
public string Filename { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("primary")]
|
||||||
|
public bool Primary { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("size")]
|
||||||
|
public long Size { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("file_type")]
|
||||||
|
public string FileType { get; set; }
|
||||||
|
}
|
||||||
11
Moonlight/App/ApiClients/Telemetry/Requests/TelemetryData.cs
Normal file
11
Moonlight/App/ApiClients/Telemetry/Requests/TelemetryData.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Moonlight.App.ApiClients.Telemetry.Requests;
|
||||||
|
|
||||||
|
public class TelemetryData
|
||||||
|
{
|
||||||
|
public string AppUrl { get; set; } = "";
|
||||||
|
public int Servers { get; set; }
|
||||||
|
public int Nodes { get; set; }
|
||||||
|
public int Users { get; set; }
|
||||||
|
public int Databases { get; set; }
|
||||||
|
public int Webspaces { get; set; }
|
||||||
|
}
|
||||||
52
Moonlight/App/ApiClients/Telemetry/TelemetryApiHelper.cs
Normal file
52
Moonlight/App/ApiClients/Telemetry/TelemetryApiHelper.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using RestSharp;
|
||||||
|
|
||||||
|
namespace Moonlight.App.ApiClients.Telemetry;
|
||||||
|
|
||||||
|
public class TelemetryApiHelper
|
||||||
|
{
|
||||||
|
private readonly RestClient Client;
|
||||||
|
|
||||||
|
public TelemetryApiHelper()
|
||||||
|
{
|
||||||
|
Client = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Post(string resource, object? body)
|
||||||
|
{
|
||||||
|
var request = CreateRequest(resource);
|
||||||
|
|
||||||
|
request.Method = Method.Post;
|
||||||
|
|
||||||
|
request.AddParameter("application/json", JsonConvert.SerializeObject(body), ParameterType.RequestBody);
|
||||||
|
|
||||||
|
var response = await Client.ExecuteAsync(request);
|
||||||
|
|
||||||
|
if (!response.IsSuccessful)
|
||||||
|
{
|
||||||
|
if (response.StatusCode != 0)
|
||||||
|
{
|
||||||
|
throw new TelemetryException(
|
||||||
|
$"An error occured: ({response.StatusCode}) {response.Content}",
|
||||||
|
(int)response.StatusCode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"An internal error occured: {response.ErrorMessage}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestRequest CreateRequest(string resource)
|
||||||
|
{
|
||||||
|
var url = "https://telemetry.moonlightpanel.xyz/" + resource;
|
||||||
|
|
||||||
|
var request = new RestRequest(url)
|
||||||
|
{
|
||||||
|
Timeout = 3000000
|
||||||
|
};
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
Moonlight/App/ApiClients/Telemetry/TelemetryException.cs
Normal file
32
Moonlight/App/ApiClients/Telemetry/TelemetryException.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace Moonlight.App.ApiClients.Telemetry;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class TelemetryException : Exception
|
||||||
|
{
|
||||||
|
public int StatusCode { get; set; }
|
||||||
|
|
||||||
|
public TelemetryException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public TelemetryException(string message, int statusCode) : base(message)
|
||||||
|
{
|
||||||
|
StatusCode = statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TelemetryException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public TelemetryException(string message, Exception inner) : base(message, inner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TelemetryException(
|
||||||
|
SerializationInfo info,
|
||||||
|
StreamingContext context) : base(info, context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -209,7 +209,7 @@ public class WingsApiHelper
|
|||||||
|
|
||||||
var request = new RestRequest(url)
|
var request = new RestRequest(url)
|
||||||
{
|
{
|
||||||
Timeout = 60 * 15
|
Timeout = 300000
|
||||||
};
|
};
|
||||||
|
|
||||||
request.AddHeader("Content-Type", "application/json");
|
request.AddHeader("Content-Type", "application/json");
|
||||||
|
|||||||
369
Moonlight/App/Configuration/ConfigV1.cs
Normal file
369
Moonlight/App/Configuration/ConfigV1.cs
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Configuration;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
public class ConfigV1
|
||||||
|
{
|
||||||
|
[JsonProperty("Moonlight")]
|
||||||
|
public MoonlightData Moonlight { get; set; } = new();
|
||||||
|
|
||||||
|
public class MoonlightData
|
||||||
|
{
|
||||||
|
[JsonProperty("AppUrl")]
|
||||||
|
[Description("The url moonlight is accesible with from the internet")]
|
||||||
|
public string AppUrl { get; set; } = "http://your-moonlight-url-without-slash";
|
||||||
|
|
||||||
|
[JsonProperty("EnableLatencyCheck")]
|
||||||
|
[Description(
|
||||||
|
"This will enable a latency check for connections to moonlight. Users with an too high latency will be warned that moonlight might be buggy for them")]
|
||||||
|
public bool EnableLatencyCheck { get; set; } = true;
|
||||||
|
|
||||||
|
[JsonProperty("LatencyCheckThreshold")]
|
||||||
|
[Description("Specify the latency threshold which has to be reached in order to trigger the warning message")]
|
||||||
|
public int LatencyCheckThreshold { get; set; } = 1000;
|
||||||
|
|
||||||
|
[JsonProperty("Auth")] public AuthData Auth { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Database")] public DatabaseData Database { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("DiscordBotApi")] public DiscordBotApiData DiscordBotApi { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("DiscordBot")] public DiscordBotData DiscordBot { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Domains")] public DomainsData Domains { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Html")] public HtmlData Html { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Marketing")] public MarketingData Marketing { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("OAuth2")] public OAuth2Data OAuth2 { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Security")] public SecurityData Security { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Mail")] public MailData Mail { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Cleanup")] public CleanupData Cleanup { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("DiscordNotifications")] public DiscordNotificationsData DiscordNotifications { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Statistics")] public StatisticsData Statistics { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Rating")] public RatingData Rating { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("SmartDeploy")] public SmartDeployData SmartDeploy { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Sentry")] public SentryData Sentry { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Stripe")] public StripeData Stripe { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Tickets")] public TicketsData Tickets { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TicketsData
|
||||||
|
{
|
||||||
|
[JsonProperty("WelcomeMessage")]
|
||||||
|
[Description("The message that will be sent when a user created a ticket")]
|
||||||
|
public string WelcomeMessage { get; set; } = "Welcome to the support";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StripeData
|
||||||
|
{
|
||||||
|
[JsonProperty("ApiKey")]
|
||||||
|
[Description("Put here your stripe api key if you add subscriptions. Currently the only billing option is stripe which is enabled by default and cannot be turned off. This feature is still experimental")]
|
||||||
|
public string ApiKey { get; set; } = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AuthData
|
||||||
|
{
|
||||||
|
[JsonProperty("DenyLogin")]
|
||||||
|
[Description("Prevent every new login")]
|
||||||
|
public bool DenyLogin { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("DenyRegister")]
|
||||||
|
[Description("Prevent every new user to register")]
|
||||||
|
public bool DenyRegister { get; set; } = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CleanupData
|
||||||
|
{
|
||||||
|
[JsonProperty("Cpu")]
|
||||||
|
[Description("The maximum amount of cpu usage in percent a node is allowed to use before the cleanup starts")]
|
||||||
|
public long Cpu { get; set; } = 90;
|
||||||
|
|
||||||
|
[JsonProperty("Memory")]
|
||||||
|
[Description("The minumum amount of memory in megabytes avaliable before the cleanup starts")]
|
||||||
|
public long Memory { get; set; } = 8192;
|
||||||
|
|
||||||
|
[JsonProperty("Wait")]
|
||||||
|
[Description("The delay between every cleanup check in minutes")]
|
||||||
|
public long Wait { get; set; } = 15;
|
||||||
|
|
||||||
|
[JsonProperty("Uptime")]
|
||||||
|
[Description("The maximum uptime of any server in hours before it the server restarted by the cleanup system")]
|
||||||
|
public long Uptime { get; set; } = 6;
|
||||||
|
|
||||||
|
[JsonProperty("Enable")]
|
||||||
|
[Description("The cleanup system provides a fair way for stopping unused servers and staying stable even with overallocation. A detailed explanation: docs.endelon-hosting.de/erklaerungen/cleanup")]
|
||||||
|
public bool Enable { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("MinUptime")]
|
||||||
|
[Description("The minumum uptime of a server in minutes to prevent stopping servers which just started")]
|
||||||
|
public long MinUptime { get; set; } = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DatabaseData
|
||||||
|
{
|
||||||
|
[JsonProperty("Database")] public string Database { get; set; } = "moonlight_db";
|
||||||
|
|
||||||
|
[JsonProperty("Host")] public string Host { get; set; } = "your.database.host";
|
||||||
|
|
||||||
|
[JsonProperty("Password")]
|
||||||
|
[Blur]
|
||||||
|
public string Password { get; set; } = "secret";
|
||||||
|
|
||||||
|
[JsonProperty("Port")] public long Port { get; set; } = 3306;
|
||||||
|
|
||||||
|
[JsonProperty("Username")] public string Username { get; set; } = "moonlight_user";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DiscordBotApiData
|
||||||
|
{
|
||||||
|
[JsonProperty("Enable")]
|
||||||
|
[Description("Enable the discord bot api. Currently only DatBot is using this api")]
|
||||||
|
public bool Enable { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("Token")]
|
||||||
|
[Description("Specify the token the api client needs to provide")]
|
||||||
|
[Blur]
|
||||||
|
public string Token { get; set; } = Guid.NewGuid().ToString();
|
||||||
|
}
|
||||||
|
public class DiscordBotData
|
||||||
|
{
|
||||||
|
[JsonProperty("Enable")]
|
||||||
|
[Description("The discord bot can be used to allow customers to manage their servers via discord")]
|
||||||
|
public bool Enable { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("Token")]
|
||||||
|
[Description("Your discord bot token goes here")]
|
||||||
|
[Blur]
|
||||||
|
public string Token { get; set; } = "discord token here";
|
||||||
|
|
||||||
|
[JsonProperty("PowerActions")]
|
||||||
|
[Description("Enable actions like starting and stopping servers")]
|
||||||
|
public bool PowerActions { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("SendCommands")]
|
||||||
|
[Description("Allow users to send commands to their servers")]
|
||||||
|
public bool SendCommands { get; set; } = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DiscordNotificationsData
|
||||||
|
{
|
||||||
|
[JsonProperty("Enable")]
|
||||||
|
[Description("The discord notification system sends you a message everytime a event like a new support chat message is triggered with usefull data describing the event")]
|
||||||
|
public bool Enable { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("WebHook")]
|
||||||
|
[Description("The discord webhook the notifications are being sent to")]
|
||||||
|
[Blur]
|
||||||
|
public string WebHook { get; set; } = "http://your-discord-webhook-url";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DomainsData
|
||||||
|
{
|
||||||
|
[JsonProperty("Enable")]
|
||||||
|
[Description("This enables the domain system")]
|
||||||
|
public bool Enable { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("AccountId")]
|
||||||
|
[Description("This option specifies the cloudflare account id")]
|
||||||
|
public string AccountId { get; set; } = "cloudflare acc id";
|
||||||
|
|
||||||
|
[JsonProperty("Email")]
|
||||||
|
[Description("This specifies the cloudflare email to use for communicating with the cloudflare api")]
|
||||||
|
public string Email { get; set; } = "cloudflare@acc.email";
|
||||||
|
|
||||||
|
[JsonProperty("Key")]
|
||||||
|
[Description("Your cloudflare api key goes here")]
|
||||||
|
[Blur]
|
||||||
|
public string Key { get; set; } = "secret";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HtmlData
|
||||||
|
{
|
||||||
|
[JsonProperty("Headers")] public HeadersData Headers { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HeadersData
|
||||||
|
{
|
||||||
|
[JsonProperty("Color")]
|
||||||
|
[Description("This specifies the color of the embed generated by platforms like discord when someone posts a link to your moonlight instance")]
|
||||||
|
public string Color { get; set; } = "#4b27e8";
|
||||||
|
|
||||||
|
[JsonProperty("Description")]
|
||||||
|
[Description("This specifies the description text of the embed generated by platforms like discord when someone posts a link to your moonlight instance and can also help google to index your moonlight instance correctly")]
|
||||||
|
public string Description { get; set; } = "the next generation hosting panel";
|
||||||
|
|
||||||
|
[JsonProperty("Keywords")]
|
||||||
|
[Description("To help search engines like google to index your moonlight instance correctly you can specify keywords seperated by a comma here")]
|
||||||
|
public string Keywords { get; set; } = "moonlight";
|
||||||
|
|
||||||
|
[JsonProperty("Title")]
|
||||||
|
[Description("This specifies the title of the embed generated by platforms like discord when someone posts a link to your moonlight instance")]
|
||||||
|
public string Title { get; set; } = "Moonlight - endelon.link";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MailData
|
||||||
|
{
|
||||||
|
[JsonProperty("Email")] public string Email { get; set; } = "username@your.mail.host";
|
||||||
|
|
||||||
|
[JsonProperty("Server")] public string Server { get; set; } = "your.mail.host";
|
||||||
|
|
||||||
|
[JsonProperty("Password")]
|
||||||
|
[Blur]
|
||||||
|
public string Password { get; set; } = "secret";
|
||||||
|
|
||||||
|
[JsonProperty("Port")] public int Port { get; set; } = 465;
|
||||||
|
|
||||||
|
[JsonProperty("Ssl")] public bool Ssl { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MarketingData
|
||||||
|
{
|
||||||
|
[JsonProperty("BrandName")] public string BrandName { get; set; } = "Endelon Hosting";
|
||||||
|
|
||||||
|
[JsonProperty("Imprint")] public string Imprint { get; set; } = "https://your-site.xyz/imprint";
|
||||||
|
|
||||||
|
[JsonProperty("Privacy")] public string Privacy { get; set; } = "https://your-site.xyz/privacy";
|
||||||
|
[JsonProperty("About")] public string About { get; set; } = "https://your-site.xyz/about";
|
||||||
|
[JsonProperty("Website")] public string Website { get; set; } = "https://your-site.xyz";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OAuth2Data
|
||||||
|
{
|
||||||
|
[JsonProperty("OverrideUrl")]
|
||||||
|
[Description("This overrides the redirect url which would be typicaly the app url")]
|
||||||
|
public string OverrideUrl { get; set; } = "https://only-for-development.cases";
|
||||||
|
|
||||||
|
[JsonProperty("EnableOverrideUrl")]
|
||||||
|
[Description("This enables the url override")]
|
||||||
|
public bool EnableOverrideUrl { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("Providers")]
|
||||||
|
public OAuth2ProviderData[] Providers { get; set; } = Array.Empty<OAuth2ProviderData>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OAuth2ProviderData
|
||||||
|
{
|
||||||
|
[JsonProperty("Id")] public string Id { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("ClientId")] public string ClientId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("ClientSecret")]
|
||||||
|
[Blur]
|
||||||
|
public string ClientSecret { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RatingData
|
||||||
|
{
|
||||||
|
[JsonProperty("Enabled")]
|
||||||
|
[Description("The rating systems shows a user who is registered longer than the set amout of days a popup to rate this platform if he hasnt rated it before")]
|
||||||
|
public bool Enabled { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("Url")]
|
||||||
|
[Description("This is the url a user who rated above a set limit is shown to rate you again. Its recommended to put your google or trustpilot rate link here")]
|
||||||
|
public string Url { get; set; } = "https://link-to-google-or-smth";
|
||||||
|
|
||||||
|
[JsonProperty("MinRating")]
|
||||||
|
[Description("The minimum star count on the rating ranging from 1 to 5")]
|
||||||
|
public int MinRating { get; set; } = 4;
|
||||||
|
|
||||||
|
[JsonProperty("DaysSince")]
|
||||||
|
[Description("The days a user has to be registered to even be able to get this popup")]
|
||||||
|
public int DaysSince { get; set; } = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SecurityData
|
||||||
|
{
|
||||||
|
[JsonProperty("Token")]
|
||||||
|
[Description("This is the moonlight app token. It is used to encrypt and decrypt data and validate tokens and sessions")]
|
||||||
|
[Blur]
|
||||||
|
public string Token { get; set; } = Guid.NewGuid().ToString();
|
||||||
|
|
||||||
|
[JsonProperty("MalwareCheckOnStart")]
|
||||||
|
[Description(
|
||||||
|
"This option will enable the scanning for malware on every server before it has been started and if something has been found, the power action will be canceled")]
|
||||||
|
public bool MalwareCheckOnStart { get; set; } = true;
|
||||||
|
|
||||||
|
[JsonProperty("BlockIpDuration")]
|
||||||
|
[Description("The duration in minutes a ip will be blocked by the anti ddos system")]
|
||||||
|
public int BlockIpDuration { get; set; } = 15;
|
||||||
|
|
||||||
|
[JsonProperty("ReCaptcha")] public ReCaptchaData ReCaptcha { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("BlockDatacenterIps")]
|
||||||
|
[Description("If this option is enabled, users with an ip from datacenters will not be able to access the panel")]
|
||||||
|
public bool BlockDatacenterIps { get; set; } = true;
|
||||||
|
|
||||||
|
[JsonProperty("AllowCloudflareIps")]
|
||||||
|
[Description("Allow cloudflare ips to bypass the datacenter ip check")]
|
||||||
|
public bool AllowCloudflareIps { get; set; } = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReCaptchaData
|
||||||
|
{
|
||||||
|
[JsonProperty("Enable")]
|
||||||
|
[Description("Enables repatcha at places like the register page. For information how to get your recaptcha credentails go to google.com/recaptcha/about/")]
|
||||||
|
public bool Enable { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("SiteKey")]
|
||||||
|
[Blur]
|
||||||
|
public string SiteKey { get; set; } = "recaptcha site key here";
|
||||||
|
|
||||||
|
[JsonProperty("SecretKey")]
|
||||||
|
[Blur]
|
||||||
|
public string SecretKey { get; set; } = "recaptcha secret here";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SentryData
|
||||||
|
{
|
||||||
|
[JsonProperty("Enable")]
|
||||||
|
[Description("Sentry is a way to monitor application crashes and performance issues in real time. Enable this option only if you set a sentry dsn")]
|
||||||
|
public bool Enable { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("Dsn")]
|
||||||
|
[Description("The dsn is the key moonlight needs to communicate with your sentry instance")]
|
||||||
|
[Blur]
|
||||||
|
public string Dsn { get; set; } = "http://your-sentry-url-here";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SmartDeployData
|
||||||
|
{
|
||||||
|
[JsonProperty("Server")] public SmartDeployServerData Server { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SmartDeployServerData
|
||||||
|
{
|
||||||
|
[JsonProperty("EnableOverride")] public bool EnableOverride { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("OverrideNode")] public long OverrideNode { get; set; } = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StatisticsData
|
||||||
|
{
|
||||||
|
[JsonProperty("Enabled")] public bool Enabled { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("Wait")] public long Wait { get; set; } = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SellPassData
|
||||||
|
{
|
||||||
|
[JsonProperty("Enable")] public bool Enable { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("Url")] public string Url { get; set; } = "https://not-implemented-yet";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Moonlight.App.Database.Entities;
|
using Moonlight.App.Database.Entities;
|
||||||
using Moonlight.App.Database.Entities.LogsEntries;
|
|
||||||
using Moonlight.App.Database.Entities.Notification;
|
using Moonlight.App.Database.Entities.Notification;
|
||||||
using Moonlight.App.Database.Interceptors;
|
using Moonlight.App.Database.Interceptors;
|
||||||
using Moonlight.App.Models.Misc;
|
|
||||||
using Moonlight.App.Services;
|
using Moonlight.App.Services;
|
||||||
|
|
||||||
namespace Moonlight.App.Database;
|
namespace Moonlight.App.Database;
|
||||||
@@ -27,10 +25,6 @@ public class DataContext : DbContext
|
|||||||
public DbSet<ServerVariable> ServerVariables { get; set; }
|
public DbSet<ServerVariable> ServerVariables { get; set; }
|
||||||
public DbSet<User> Users { get; set; }
|
public DbSet<User> Users { get; set; }
|
||||||
public DbSet<LoadingMessage> LoadingMessages { get; set; }
|
public DbSet<LoadingMessage> LoadingMessages { get; set; }
|
||||||
public DbSet<AuditLogEntry> AuditLog { get; set; }
|
|
||||||
public DbSet<ErrorLogEntry> ErrorLog { get; set; }
|
|
||||||
public DbSet<SecurityLogEntry> SecurityLog { get; set; }
|
|
||||||
|
|
||||||
public DbSet<SharedDomain> SharedDomains { get; set; }
|
public DbSet<SharedDomain> SharedDomains { get; set; }
|
||||||
public DbSet<Domain> Domains { get; set; }
|
public DbSet<Domain> Domains { get; set; }
|
||||||
public DbSet<Revoke> Revokes { get; set; }
|
public DbSet<Revoke> Revokes { get; set; }
|
||||||
@@ -46,20 +40,27 @@ public class DataContext : DbContext
|
|||||||
public DbSet<WebSpace> WebSpaces { get; set; }
|
public DbSet<WebSpace> WebSpaces { get; set; }
|
||||||
public DbSet<SupportChatMessage> SupportChatMessages { get; set; }
|
public DbSet<SupportChatMessage> SupportChatMessages { get; set; }
|
||||||
public DbSet<IpBan> IpBans { get; set; }
|
public DbSet<IpBan> IpBans { get; set; }
|
||||||
|
public DbSet<PermissionGroup> PermissionGroups { get; set; }
|
||||||
|
public DbSet<SecurityLog> SecurityLogs { get; set; }
|
||||||
|
public DbSet<BlocklistIp> BlocklistIps { get; set; }
|
||||||
|
public DbSet<WhitelistIp> WhitelistIps { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Ticket> Tickets { get; set; }
|
||||||
|
public DbSet<TicketMessage> TicketMessages { get; set; }
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
if (!optionsBuilder.IsConfigured)
|
if (!optionsBuilder.IsConfigured)
|
||||||
{
|
{
|
||||||
var config = ConfigService
|
var config = ConfigService
|
||||||
.GetSection("Moonlight")
|
.Get()
|
||||||
.GetSection("Database");
|
.Moonlight.Database;
|
||||||
|
|
||||||
var connectionString = $"host={config.GetValue<string>("Host")};" +
|
var connectionString = $"host={config.Host};" +
|
||||||
$"port={config.GetValue<int>("Port")};" +
|
$"port={config.Port};" +
|
||||||
$"database={config.GetValue<string>("Database")};" +
|
$"database={config.Database};" +
|
||||||
$"uid={config.GetValue<string>("Username")};" +
|
$"uid={config.Username};" +
|
||||||
$"pwd={config.GetValue<string>("Password")}";
|
$"pwd={config.Password}";
|
||||||
|
|
||||||
optionsBuilder.UseMySql(
|
optionsBuilder.UseMySql(
|
||||||
connectionString,
|
connectionString,
|
||||||
|
|||||||
10
Moonlight/App/Database/Entities/BlocklistIp.cs
Normal file
10
Moonlight/App/Database/Entities/BlocklistIp.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
public class BlocklistIp
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Ip { get; set; } = "";
|
||||||
|
public DateTime ExpiresAt { get; set; }
|
||||||
|
public long Packets { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
}
|
||||||
@@ -20,4 +20,5 @@ public class Image
|
|||||||
public List<DockerImage> DockerImages { get; set; } = new();
|
public List<DockerImage> DockerImages { get; set; } = new();
|
||||||
public List<ImageVariable> Variables { get; set; } = new();
|
public List<ImageVariable> Variables { get; set; } = new();
|
||||||
public string TagsJson { get; set; } = "";
|
public string TagsJson { get; set; } = "";
|
||||||
|
public string BackgroundImageUrl { get; set; } = "";
|
||||||
}
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using Moonlight.App.Models.Misc;
|
|
||||||
|
|
||||||
namespace Moonlight.App.Database.Entities.LogsEntries;
|
|
||||||
|
|
||||||
public class AuditLogEntry
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public AuditLogType Type { get; set; }
|
|
||||||
public string JsonData { get; set; } = "";
|
|
||||||
public bool System { get; set; }
|
|
||||||
public string Ip { get; set; } = "";
|
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace Moonlight.App.Database.Entities.LogsEntries;
|
|
||||||
|
|
||||||
public class ErrorLogEntry
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public string Stacktrace { get; set; } = "";
|
|
||||||
public bool System { get; set; }
|
|
||||||
public string JsonData { get; set; } = "";
|
|
||||||
public string Ip { get; set; } = "";
|
|
||||||
public string Class { get; set; } = "";
|
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using Moonlight.App.Models.Misc;
|
|
||||||
|
|
||||||
namespace Moonlight.App.Database.Entities.LogsEntries;
|
|
||||||
|
|
||||||
public class SecurityLogEntry
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public bool System { get; set; }
|
|
||||||
public string Ip { get; set; } = "";
|
|
||||||
public SecurityLogType Type { get; set; }
|
|
||||||
public string JsonData { get; set; } = "";
|
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
8
Moonlight/App/Database/Entities/PermissionGroup.cs
Normal file
8
Moonlight/App/Database/Entities/PermissionGroup.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
public class PermissionGroup
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public byte[] Permissions { get; set; } = Array.Empty<byte>();
|
||||||
|
}
|
||||||
8
Moonlight/App/Database/Entities/SecurityLog.cs
Normal file
8
Moonlight/App/Database/Entities/SecurityLog.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
public class SecurityLog
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Text { get; set; } = "";
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
}
|
||||||
@@ -13,6 +13,8 @@ public class Server
|
|||||||
public string OverrideStartup { get; set; } = "";
|
public string OverrideStartup { get; set; } = "";
|
||||||
public bool Installing { get; set; } = false;
|
public bool Installing { get; set; } = false;
|
||||||
public bool Suspended { get; set; } = false;
|
public bool Suspended { get; set; } = false;
|
||||||
|
public bool IsArchived { get; set; } = false;
|
||||||
|
public ServerBackup? Archive { get; set; } = null;
|
||||||
|
|
||||||
public List<ServerVariable> Variables { get; set; } = new();
|
public List<ServerVariable> Variables { get; set; } = new();
|
||||||
public List<ServerBackup> Backups { get; set; } = new();
|
public List<ServerBackup> Backups { get; set; } = new();
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
namespace Moonlight.App.Database.Entities;
|
using Moonlight.App.Models.Misc;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
public class Subscription
|
public class Subscription
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Name { get; set; } = "";
|
public string Name { get; set; } = "";
|
||||||
public string Description { get; set; } = "";
|
public string Description { get; set; } = "";
|
||||||
|
public Currency Currency { get; set; } = Currency.USD;
|
||||||
|
public double Price { get; set; }
|
||||||
|
public string StripeProductId { get; set; } = "";
|
||||||
|
public string StripePriceId { get; set; } = "";
|
||||||
public string LimitsJson { get; set; } = "";
|
public string LimitsJson { get; set; } = "";
|
||||||
|
public int Duration { get; set; } = 30;
|
||||||
}
|
}
|
||||||
19
Moonlight/App/Database/Entities/Ticket.cs
Normal file
19
Moonlight/App/Database/Entities/Ticket.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using Moonlight.App.Models.Misc;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
public class Ticket
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string IssueTopic { get; set; } = "";
|
||||||
|
public string IssueDescription { get; set; } = "";
|
||||||
|
public string IssueTries { get; set; } = "";
|
||||||
|
public User CreatedBy { get; set; }
|
||||||
|
public User? AssignedTo { get; set; }
|
||||||
|
public TicketPriority Priority { get; set; }
|
||||||
|
public TicketStatus Status { get; set; }
|
||||||
|
public TicketSubject Subject { get; set; }
|
||||||
|
public int SubjectId { get; set; }
|
||||||
|
public List<TicketMessage> Messages { get; set; } = new();
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
}
|
||||||
14
Moonlight/App/Database/Entities/TicketMessage.cs
Normal file
14
Moonlight/App/Database/Entities/TicketMessage.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
public class TicketMessage
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Content { get; set; } = "";
|
||||||
|
public string? AttachmentUrl { get; set; }
|
||||||
|
public User? Sender { get; set; }
|
||||||
|
public bool IsSystemMessage { get; set; }
|
||||||
|
public bool IsEdited { get; set; }
|
||||||
|
public bool IsSupportMessage { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Moonlight.App.Models.Misc;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Moonlight.App.Models.Misc;
|
||||||
|
|
||||||
namespace Moonlight.App.Database.Entities;
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
@@ -23,7 +24,9 @@ public class User
|
|||||||
public string State { get; set; } = "";
|
public string State { get; set; } = "";
|
||||||
|
|
||||||
public string Country { get; set; } = "";
|
public string Country { get; set; } = "";
|
||||||
|
|
||||||
|
public string ServerListLayoutJson { get; set; } = "";
|
||||||
|
|
||||||
// States
|
// States
|
||||||
|
|
||||||
public UserStatus Status { get; set; } = UserStatus.Unverified;
|
public UserStatus Status { get; set; } = UserStatus.Unverified;
|
||||||
@@ -31,11 +34,14 @@ public class User
|
|||||||
public bool SupportPending { get; set; } = false;
|
public bool SupportPending { get; set; } = false;
|
||||||
public bool HasRated { get; set; } = false;
|
public bool HasRated { get; set; } = false;
|
||||||
public int Rating { get; set; } = 0;
|
public int Rating { get; set; } = 0;
|
||||||
|
public bool StreamerMode { get; set; } = false;
|
||||||
|
|
||||||
// Security
|
// Security
|
||||||
public bool TotpEnabled { get; set; } = false;
|
public bool TotpEnabled { get; set; } = false;
|
||||||
public string TotpSecret { get; set; } = "";
|
public string TotpSecret { get; set; } = "";
|
||||||
public DateTime TokenValidTime { get; set; } = DateTime.UtcNow;
|
public DateTime TokenValidTime { get; set; } = DateTime.UtcNow;
|
||||||
|
public byte[] Permissions { get; set; } = Array.Empty<byte>();
|
||||||
|
public PermissionGroup? PermissionGroup { get; set; }
|
||||||
|
|
||||||
// Discord
|
// Discord
|
||||||
public ulong DiscordId { get; set; }
|
public ulong DiscordId { get; set; }
|
||||||
@@ -43,10 +49,15 @@ public class User
|
|||||||
// Date stuff
|
// Date stuff
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
public DateTime LastVisitedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
// Subscriptions
|
// Subscriptions
|
||||||
|
|
||||||
public Subscription? CurrentSubscription { get; set; } = null;
|
public Subscription? CurrentSubscription { get; set; } = null;
|
||||||
public DateTime SubscriptionSince { get; set; } = DateTime.Now;
|
public DateTime SubscriptionSince { get; set; } = DateTime.UtcNow;
|
||||||
public int SubscriptionDuration { get; set; }
|
public DateTime SubscriptionExpires { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
// Ip logs
|
||||||
|
public string RegisterIp { get; set; } = "";
|
||||||
|
public string LastIp { get; set; } = "";
|
||||||
}
|
}
|
||||||
7
Moonlight/App/Database/Entities/WhitelistIp.cs
Normal file
7
Moonlight/App/Database/Entities/WhitelistIp.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
public class WhitelistIp
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Ip { get; set; } = "";
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using Logging.Net;
|
|
||||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
|
using Moonlight.App.Helpers;
|
||||||
|
|
||||||
namespace Moonlight.App.Database.Interceptors;
|
namespace Moonlight.App.Database.Interceptors;
|
||||||
|
|
||||||
|
|||||||
1056
Moonlight/App/Database/Migrations/20230609202138_AddBackgroundImageUrlImage.Designer.cs
generated
Normal file
1056
Moonlight/App/Database/Migrations/20230609202138_AddBackgroundImageUrlImage.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddBackgroundImageUrlImage : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "BackgroundImageUrl",
|
||||||
|
table: "Images",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "BackgroundImageUrl",
|
||||||
|
table: "Images");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1059
Moonlight/App/Database/Migrations/20230611152138_AddLastVisitedTimestamp.Designer.cs
generated
Normal file
1059
Moonlight/App/Database/Migrations/20230611152138_AddLastVisitedTimestamp.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddLastVisitedTimestamp : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "LastVisitedAt",
|
||||||
|
table: "Users",
|
||||||
|
type: "datetime(6)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LastVisitedAt",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1073
Moonlight/App/Database/Migrations/20230614010621_AddedServerAchive.Designer.cs
generated
Normal file
1073
Moonlight/App/Database/Migrations/20230614010621_AddedServerAchive.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedServerAchive : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "ArchiveId",
|
||||||
|
table: "Servers",
|
||||||
|
type: "int",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsArchived",
|
||||||
|
table: "Servers",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Servers_ArchiveId",
|
||||||
|
table: "Servers",
|
||||||
|
column: "ArchiveId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Servers_ServerBackups_ArchiveId",
|
||||||
|
table: "Servers",
|
||||||
|
column: "ArchiveId",
|
||||||
|
principalTable: "ServerBackups",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Servers_ServerBackups_ArchiveId",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Servers_ArchiveId",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ArchiveId",
|
||||||
|
table: "Servers");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsArchived",
|
||||||
|
table: "Servers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1077
Moonlight/App/Database/Migrations/20230623235512_AddedServerListLayoutToUser.Designer.cs
generated
Normal file
1077
Moonlight/App/Database/Migrations/20230623235512_AddedServerListLayoutToUser.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedServerListLayoutToUser : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "ServerListLayoutJson",
|
||||||
|
table: "Users",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ServerListLayoutJson",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1080
Moonlight/App/Database/Migrations/20230625190428_AddedStreamerMode.Designer.cs
generated
Normal file
1080
Moonlight/App/Database/Migrations/20230625190428_AddedStreamerMode.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedStreamerMode : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "StreamerMode",
|
||||||
|
table: "Users",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "StreamerMode",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1088
Moonlight/App/Database/Migrations/20230703175432_AddedIpLogsForUser.Designer.cs
generated
Normal file
1088
Moonlight/App/Database/Migrations/20230703175432_AddedIpLogsForUser.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedIpLogsForUser : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "LastIp",
|
||||||
|
table: "Users",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "RegisterIp",
|
||||||
|
table: "Users",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LastIp",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "RegisterIp",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1105
Moonlight/App/Database/Migrations/20230705171914_AddedStripeIntegration.Designer.cs
generated
Normal file
1105
Moonlight/App/Database/Migrations/20230705171914_AddedStripeIntegration.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedStripeIntegration : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "SubscriptionDuration",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "SubscriptionExpires",
|
||||||
|
table: "Users",
|
||||||
|
type: "datetime(6)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "Currency",
|
||||||
|
table: "Subscriptions",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "Duration",
|
||||||
|
table: "Subscriptions",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<double>(
|
||||||
|
name: "Price",
|
||||||
|
table: "Subscriptions",
|
||||||
|
type: "double",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0.0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "StripePriceId",
|
||||||
|
table: "Subscriptions",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "StripeProductId",
|
||||||
|
table: "Subscriptions",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "SubscriptionExpires",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Currency",
|
||||||
|
table: "Subscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Duration",
|
||||||
|
table: "Subscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Price",
|
||||||
|
table: "Subscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "StripePriceId",
|
||||||
|
table: "Subscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "StripeProductId",
|
||||||
|
table: "Subscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "SubscriptionDuration",
|
||||||
|
table: "Users",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1109
Moonlight/App/Database/Migrations/20230715095531_AddPermissions.Designer.cs
generated
Normal file
1109
Moonlight/App/Database/Migrations/20230715095531_AddPermissions.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddPermissions : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<byte[]>(
|
||||||
|
name: "Permissions",
|
||||||
|
table: "Users",
|
||||||
|
type: "longblob",
|
||||||
|
nullable: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Permissions",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1139
Moonlight/App/Database/Migrations/20230715214550_AddPermissionGroup.Designer.cs
generated
Normal file
1139
Moonlight/App/Database/Migrations/20230715214550_AddPermissionGroup.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddPermissionGroup : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "PermissionGroupId",
|
||||||
|
table: "Users",
|
||||||
|
type: "int",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PermissionGroups",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Name = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Permissions = table.Column<byte[]>(type: "longblob", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PermissionGroups", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Users_PermissionGroupId",
|
||||||
|
table: "Users",
|
||||||
|
column: "PermissionGroupId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Users_PermissionGroups_PermissionGroupId",
|
||||||
|
table: "Users",
|
||||||
|
column: "PermissionGroupId",
|
||||||
|
principalTable: "PermissionGroups",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Users_PermissionGroups_PermissionGroupId",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PermissionGroups");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Users_PermissionGroupId",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PermissionGroupId",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1068
Moonlight/App/Database/Migrations/20230718123232_RemovedOldLogsAndAddedErrorLog.Designer.cs
generated
Normal file
1068
Moonlight/App/Database/Migrations/20230718123232_RemovedOldLogsAndAddedErrorLog.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,111 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class RemovedOldLogsAndAddedErrorLog : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AuditLog");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ErrorLog");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SecurityLog");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SecurityLogs",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Text = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SecurityLogs", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SecurityLogs");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AuditLog",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
Ip = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
JsonData = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
System = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||||
|
Type = table.Column<int>(type: "int", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AuditLog", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ErrorLog",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Class = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
Ip = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
JsonData = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Stacktrace = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
System = table.Column<bool>(type: "tinyint(1)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ErrorLog", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SecurityLog",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
Ip = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
JsonData = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
System = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||||
|
Type = table.Column<int>(type: "int", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SecurityLog", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1107
Moonlight/App/Database/Migrations/20230721201950_AddIpRules.Designer.cs
generated
Normal file
1107
Moonlight/App/Database/Migrations/20230721201950_AddIpRules.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddIpRules : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "BlocklistIps",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Ip = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
ExpiresAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
Packets = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_BlocklistIps", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "WhitelistIps",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Ip = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_WhitelistIps", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "BlocklistIps");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "WhitelistIps");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1233
Moonlight/App/Database/Migrations/20230803012947_AddNewTicketModels.Designer.cs
generated
Normal file
1233
Moonlight/App/Database/Migrations/20230803012947_AddNewTicketModels.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,117 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddNewTicketModels : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Tickets",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
IssueTopic = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
IssueDescription = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
IssueTries = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
CreatedById = table.Column<int>(type: "int", nullable: false),
|
||||||
|
AssignedToId = table.Column<int>(type: "int", nullable: true),
|
||||||
|
Priority = table.Column<int>(type: "int", nullable: false),
|
||||||
|
Status = table.Column<int>(type: "int", nullable: false),
|
||||||
|
Subject = table.Column<int>(type: "int", nullable: false),
|
||||||
|
SubjectId = table.Column<int>(type: "int", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Tickets", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Tickets_Users_AssignedToId",
|
||||||
|
column: x => x.AssignedToId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Tickets_Users_CreatedById",
|
||||||
|
column: x => x.CreatedById,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "TicketMessages",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Content = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
AttachmentUrl = table.Column<string>(type: "longtext", nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
SenderId = table.Column<int>(type: "int", nullable: true),
|
||||||
|
IsSystemMessage = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||||
|
IsEdited = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||||
|
IsSupportMessage = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
TicketId = table.Column<int>(type: "int", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_TicketMessages", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TicketMessages_Tickets_TicketId",
|
||||||
|
column: x => x.TicketId,
|
||||||
|
principalTable: "Tickets",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TicketMessages_Users_SenderId",
|
||||||
|
column: x => x.SenderId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id");
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TicketMessages_SenderId",
|
||||||
|
table: "TicketMessages",
|
||||||
|
column: "SenderId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TicketMessages_TicketId",
|
||||||
|
table: "TicketMessages",
|
||||||
|
column: "TicketId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Tickets_AssignedToId",
|
||||||
|
table: "Tickets",
|
||||||
|
column: "AssignedToId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Tickets_CreatedById",
|
||||||
|
table: "Tickets",
|
||||||
|
column: "CreatedById");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "TicketMessages");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Tickets");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,30 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
.HasAnnotation("ProductVersion", "7.0.3")
|
.HasAnnotation("ProductVersion", "7.0.3")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.BlocklistIp", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("ExpiresAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Ip")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<long>("Packets")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("BlocklistIps");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.CloudPanel", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.CloudPanel", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -132,6 +156,10 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.Property<int>("Allocations")
|
b.Property<int>("Allocations")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("BackgroundImageUrl")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("ConfigFiles")
|
b.Property<string>("ConfigFiles")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
@@ -237,95 +265,6 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.ToTable("LoadingMessages");
|
b.ToTable("LoadingMessages");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.AuditLogEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("int");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("datetime(6)");
|
|
||||||
|
|
||||||
b.Property<string>("Ip")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
|
||||||
|
|
||||||
b.Property<string>("JsonData")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
|
||||||
|
|
||||||
b.Property<bool>("System")
|
|
||||||
.HasColumnType("tinyint(1)");
|
|
||||||
|
|
||||||
b.Property<int>("Type")
|
|
||||||
.HasColumnType("int");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("AuditLog");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.ErrorLogEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("int");
|
|
||||||
|
|
||||||
b.Property<string>("Class")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("datetime(6)");
|
|
||||||
|
|
||||||
b.Property<string>("Ip")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
|
||||||
|
|
||||||
b.Property<string>("JsonData")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
|
||||||
|
|
||||||
b.Property<string>("Stacktrace")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
|
||||||
|
|
||||||
b.Property<bool>("System")
|
|
||||||
.HasColumnType("tinyint(1)");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("ErrorLog");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.SecurityLogEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("int");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("datetime(6)");
|
|
||||||
|
|
||||||
b.Property<string>("Ip")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
|
||||||
|
|
||||||
b.Property<string>("JsonData")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
|
||||||
|
|
||||||
b.Property<bool>("System")
|
|
||||||
.HasColumnType("tinyint(1)");
|
|
||||||
|
|
||||||
b.Property<int>("Type")
|
|
||||||
.HasColumnType("int");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("SecurityLog");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.MySqlDatabase", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.MySqlDatabase", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -471,6 +410,25 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.ToTable("NotificationClients");
|
b.ToTable("NotificationClients");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.PermissionGroup", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<byte[]>("Permissions")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longblob");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PermissionGroups");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Revoke", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Revoke", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -486,12 +444,33 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.ToTable("Revokes");
|
b.ToTable("Revokes");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.SecurityLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("SecurityLogs");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ArchiveId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<int>("Cpu")
|
b.Property<int>("Cpu")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
@@ -507,6 +486,9 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.Property<bool>("Installing")
|
b.Property<bool>("Installing")
|
||||||
.HasColumnType("tinyint(1)");
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsArchived")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
b.Property<bool>("IsCleanupException")
|
b.Property<bool>("IsCleanupException")
|
||||||
.HasColumnType("tinyint(1)");
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
@@ -538,6 +520,8 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
b.HasIndex("ImageId");
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
b.HasIndex("MainAllocationId");
|
b.HasIndex("MainAllocationId");
|
||||||
@@ -651,10 +635,16 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Currency")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<string>("Description")
|
b.Property<string>("Description")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Duration")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<string>("LimitsJson")
|
b.Property<string>("LimitsJson")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
@@ -663,6 +653,17 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<double>("Price")
|
||||||
|
.HasColumnType("double");
|
||||||
|
|
||||||
|
b.Property<string>("StripePriceId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("StripeProductId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("Subscriptions");
|
b.ToTable("Subscriptions");
|
||||||
@@ -713,6 +714,97 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.ToTable("SupportChatMessages");
|
b.ToTable("SupportChatMessages");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Ticket", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("AssignedToId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<int>("CreatedById")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("IssueDescription")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("IssueTopic")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("IssueTries")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Subject")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("SubjectId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AssignedToId");
|
||||||
|
|
||||||
|
b.HasIndex("CreatedById");
|
||||||
|
|
||||||
|
b.ToTable("Tickets");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.TicketMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("AttachmentUrl")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEdited")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSupportMessage")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSystemMessage")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<int?>("SenderId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("TicketId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SenderId");
|
||||||
|
|
||||||
|
b.HasIndex("TicketId");
|
||||||
|
|
||||||
|
b.ToTable("TicketMessages");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -754,17 +846,39 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.Property<bool>("HasRated")
|
b.Property<bool>("HasRated")
|
||||||
.HasColumnType("tinyint(1)");
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("LastIp")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("LastName")
|
b.Property<string>("LastName")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastVisitedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
b.Property<string>("Password")
|
b.Property<string>("Password")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("PermissionGroupId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<byte[]>("Permissions")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longblob");
|
||||||
|
|
||||||
b.Property<int>("Rating")
|
b.Property<int>("Rating")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("RegisterIp")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ServerListLayoutJson")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("State")
|
b.Property<string>("State")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
@@ -772,8 +886,11 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.Property<int>("Status")
|
b.Property<int>("Status")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<int>("SubscriptionDuration")
|
b.Property<bool>("StreamerMode")
|
||||||
.HasColumnType("int");
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("SubscriptionExpires")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
b.Property<DateTime>("SubscriptionSince")
|
b.Property<DateTime>("SubscriptionSince")
|
||||||
.HasColumnType("datetime(6)");
|
.HasColumnType("datetime(6)");
|
||||||
@@ -798,6 +915,8 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
|
|
||||||
b.HasIndex("CurrentSubscriptionId");
|
b.HasIndex("CurrentSubscriptionId");
|
||||||
|
|
||||||
|
b.HasIndex("PermissionGroupId");
|
||||||
|
|
||||||
b.ToTable("Users");
|
b.ToTable("Users");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -838,6 +957,21 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.ToTable("WebSpaces");
|
b.ToTable("WebSpaces");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.WhitelistIp", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Ip")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("WhitelistIps");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.DdosAttack", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.DdosAttack", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Moonlight.App.Database.Entities.Node", "Node")
|
b.HasOne("Moonlight.App.Database.Entities.Node", "Node")
|
||||||
@@ -928,6 +1062,10 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
||||||
{
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.ServerBackup", "Archive")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ArchiveId");
|
||||||
|
|
||||||
b.HasOne("Moonlight.App.Database.Entities.Image", "Image")
|
b.HasOne("Moonlight.App.Database.Entities.Image", "Image")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("ImageId")
|
.HasForeignKey("ImageId")
|
||||||
@@ -950,6 +1088,8 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Archive");
|
||||||
|
|
||||||
b.Navigation("Image");
|
b.Navigation("Image");
|
||||||
|
|
||||||
b.Navigation("MainAllocation");
|
b.Navigation("MainAllocation");
|
||||||
@@ -990,13 +1130,49 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.Navigation("Sender");
|
b.Navigation("Sender");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Ticket", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "AssignedTo")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AssignedToId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "CreatedBy")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CreatedById")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("AssignedTo");
|
||||||
|
|
||||||
|
b.Navigation("CreatedBy");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.TicketMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Sender")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("SenderId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Ticket", null)
|
||||||
|
.WithMany("Messages")
|
||||||
|
.HasForeignKey("TicketId");
|
||||||
|
|
||||||
|
b.Navigation("Sender");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Moonlight.App.Database.Entities.Subscription", "CurrentSubscription")
|
b.HasOne("Moonlight.App.Database.Entities.Subscription", "CurrentSubscription")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CurrentSubscriptionId");
|
.HasForeignKey("CurrentSubscriptionId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.PermissionGroup", "PermissionGroup")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("PermissionGroupId");
|
||||||
|
|
||||||
b.Navigation("CurrentSubscription");
|
b.Navigation("CurrentSubscription");
|
||||||
|
|
||||||
|
b.Navigation("PermissionGroup");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b =>
|
||||||
@@ -1039,6 +1215,11 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.Navigation("Variables");
|
b.Navigation("Variables");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Ticket", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Messages");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Databases");
|
b.Navigation("Databases");
|
||||||
|
|||||||
58
Moonlight/App/Diagnostics/HealthChecks/DaemonHealthCheck.cs
Normal file
58
Moonlight/App/Diagnostics/HealthChecks/DaemonHealthCheck.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Diagnostics.HealthChecks;
|
||||||
|
|
||||||
|
public class DaemonHealthCheck : IHealthCheck
|
||||||
|
{
|
||||||
|
private readonly Repository<Node> NodeRepository;
|
||||||
|
private readonly NodeService NodeService;
|
||||||
|
|
||||||
|
public DaemonHealthCheck(Repository<Node> nodeRepository, NodeService nodeService)
|
||||||
|
{
|
||||||
|
NodeRepository = nodeRepository;
|
||||||
|
NodeService = nodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
var nodes = NodeRepository.Get().ToArray();
|
||||||
|
|
||||||
|
var results = new Dictionary<Node, bool>();
|
||||||
|
var healthCheckData = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await NodeService.GetCpuMetrics(node);
|
||||||
|
|
||||||
|
results.Add(node, true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
results.Add(node, false);
|
||||||
|
healthCheckData.Add(node.Name, e.ToStringDemystified());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var offlineNodes = results
|
||||||
|
.Where(x => !x.Value)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (offlineNodes.Length == nodes.Length)
|
||||||
|
{
|
||||||
|
return HealthCheckResult.Unhealthy("All node daemons are offline", null, healthCheckData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offlineNodes.Length == 0)
|
||||||
|
{
|
||||||
|
return HealthCheckResult.Healthy("All node daemons are online");
|
||||||
|
}
|
||||||
|
|
||||||
|
return HealthCheckResult.Degraded($"{offlineNodes.Length} node daemons are offline", null, healthCheckData);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Diagnostics.HealthChecks;
|
||||||
|
|
||||||
|
public class DatabaseHealthCheck : IHealthCheck
|
||||||
|
{
|
||||||
|
private readonly DataContext DataContext;
|
||||||
|
|
||||||
|
public DatabaseHealthCheck(DataContext dataContext)
|
||||||
|
{
|
||||||
|
DataContext = dataContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HealthCheckResult> CheckHealthAsync(
|
||||||
|
HealthCheckContext context,
|
||||||
|
CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await DataContext.Database.OpenConnectionAsync(cancellationToken);
|
||||||
|
await DataContext.Database.CloseConnectionAsync();
|
||||||
|
|
||||||
|
return HealthCheckResult.Healthy("Database is online");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return HealthCheckResult.Unhealthy("Database is offline", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
Moonlight/App/Diagnostics/HealthChecks/NodeHealthCheck.cs
Normal file
58
Moonlight/App/Diagnostics/HealthChecks/NodeHealthCheck.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Diagnostics.HealthChecks;
|
||||||
|
|
||||||
|
public class NodeHealthCheck : IHealthCheck
|
||||||
|
{
|
||||||
|
private readonly Repository<Node> NodeRepository;
|
||||||
|
private readonly NodeService NodeService;
|
||||||
|
|
||||||
|
public NodeHealthCheck(Repository<Node> nodeRepository, NodeService nodeService)
|
||||||
|
{
|
||||||
|
NodeRepository = nodeRepository;
|
||||||
|
NodeService = nodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken())
|
||||||
|
{
|
||||||
|
var nodes = NodeRepository.Get().ToArray();
|
||||||
|
|
||||||
|
var results = new Dictionary<Node, bool>();
|
||||||
|
var healthCheckData = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await NodeService.GetStatus(node);
|
||||||
|
|
||||||
|
results.Add(node, true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
results.Add(node, false);
|
||||||
|
healthCheckData.Add(node.Name, e.ToStringDemystified());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var offlineNodes = results
|
||||||
|
.Where(x => !x.Value)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (offlineNodes.Length == nodes.Length)
|
||||||
|
{
|
||||||
|
return HealthCheckResult.Unhealthy("All nodes are offline", null, healthCheckData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offlineNodes.Length == 0)
|
||||||
|
{
|
||||||
|
return HealthCheckResult.Healthy("All nodes are online");
|
||||||
|
}
|
||||||
|
|
||||||
|
return HealthCheckResult.Degraded($"{offlineNodes.Length} nodes are offline", null, healthCheckData);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Logging.Net;
|
using Moonlight.App.Helpers;
|
||||||
|
|
||||||
namespace Moonlight.App.Events;
|
namespace Moonlight.App.Events;
|
||||||
|
|
||||||
@@ -112,4 +112,22 @@ public class EventSystem
|
|||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<T> WaitForEvent<T>(string id, object handle, Func<T, bool> filter)
|
||||||
|
{
|
||||||
|
var taskCompletionSource = new TaskCompletionSource<T>();
|
||||||
|
|
||||||
|
Func<T, Task> action = async data =>
|
||||||
|
{
|
||||||
|
if (filter.Invoke(data))
|
||||||
|
{
|
||||||
|
taskCompletionSource.SetResult(data);
|
||||||
|
await Off(id, handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
On<T>(id, handle, action);
|
||||||
|
|
||||||
|
return taskCompletionSource.Task;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@ namespace Moonlight.App.Exceptions;
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class DisplayException : Exception
|
public class DisplayException : Exception
|
||||||
{
|
{
|
||||||
|
public bool DoNotTranslate { get; set; } = false;
|
||||||
|
|
||||||
//
|
//
|
||||||
// For guidelines regarding the creation of new exception types, see
|
// For guidelines regarding the creation of new exception types, see
|
||||||
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
|
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
|
||||||
@@ -19,6 +21,11 @@ public class DisplayException : Exception
|
|||||||
public DisplayException(string message) : base(message)
|
public DisplayException(string message) : base(message)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DisplayException(string message, bool doNotTranslate) : base(message)
|
||||||
|
{
|
||||||
|
DoNotTranslate = doNotTranslate;
|
||||||
|
}
|
||||||
|
|
||||||
public DisplayException(string message, Exception inner) : base(message, inner)
|
public DisplayException(string message, Exception inner) : base(message, inner)
|
||||||
{
|
{
|
||||||
|
|||||||
30
Moonlight/App/Extensions/JSRuntimeExtensions.cs
Normal file
30
Moonlight/App/Extensions/JSRuntimeExtensions.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using Microsoft.JSInterop;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Extensions;
|
||||||
|
|
||||||
|
public static class JSRuntimeExtensions
|
||||||
|
{
|
||||||
|
public static async Task InvokeVoidSafeAsync(this IJSRuntime jsRuntime, string method, params object[] args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await jsRuntime.InvokeVoidAsync(method, args);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeVoidSafe(this IJSRuntime jsRuntime, string method, params object[] args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
jsRuntime.InvokeVoidAsync(method, args);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
Moonlight/App/Helpers/AvgHelper.cs
Normal file
39
Moonlight/App/Helpers/AvgHelper.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public static class AvgHelper
|
||||||
|
{
|
||||||
|
public static StatisticsData[] Calculate(StatisticsData[] data, int splitSize = 40)
|
||||||
|
{
|
||||||
|
if (data.Length <= splitSize)
|
||||||
|
return data;
|
||||||
|
|
||||||
|
var result = new List<StatisticsData>();
|
||||||
|
|
||||||
|
var i = data.Length / (float)splitSize;
|
||||||
|
var pc = (int)Math.Round(i);
|
||||||
|
|
||||||
|
foreach (var part in data.Chunk(pc))
|
||||||
|
{
|
||||||
|
double d = 0;
|
||||||
|
var res = new StatisticsData();
|
||||||
|
|
||||||
|
foreach (var entry in part)
|
||||||
|
{
|
||||||
|
d += entry.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Chart = part.First().Chart;
|
||||||
|
res.Date = part.First().Date;
|
||||||
|
|
||||||
|
if (d == 0)
|
||||||
|
res.Value = 0;
|
||||||
|
|
||||||
|
res.Value = d / part.Length;
|
||||||
|
result.Add(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
119
Moonlight/App/Helpers/BackupHelper.cs
Normal file
119
Moonlight/App/Helpers/BackupHelper.cs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
using MySql.Data.MySqlClient;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public class BackupHelper
|
||||||
|
{
|
||||||
|
public async Task CreateBackup(string path)
|
||||||
|
{
|
||||||
|
Logger.Info("Started moonlight backup creation");
|
||||||
|
Logger.Info($"This backup will be saved to '{path}'");
|
||||||
|
|
||||||
|
var stopWatch = new Stopwatch();
|
||||||
|
stopWatch.Start();
|
||||||
|
|
||||||
|
var cachePath = PathBuilder.Dir("storage", "backups", "cache");
|
||||||
|
|
||||||
|
Directory.CreateDirectory(cachePath);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Exporting database
|
||||||
|
//
|
||||||
|
|
||||||
|
Logger.Info("Exporting database");
|
||||||
|
|
||||||
|
var configService = new ConfigService(new());
|
||||||
|
var dataContext = new DataContext(configService);
|
||||||
|
|
||||||
|
await using MySqlConnection conn = new MySqlConnection(dataContext.Database.GetConnectionString());
|
||||||
|
await using MySqlCommand cmd = new MySqlCommand();
|
||||||
|
using MySqlBackup mb = new MySqlBackup(cmd);
|
||||||
|
|
||||||
|
cmd.Connection = conn;
|
||||||
|
await conn.OpenAsync();
|
||||||
|
mb.ExportToFile(PathBuilder.File(cachePath, "database.sql"));
|
||||||
|
await conn.CloseAsync();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Saving config
|
||||||
|
//
|
||||||
|
|
||||||
|
Logger.Info("Saving configuration");
|
||||||
|
File.Copy(
|
||||||
|
PathBuilder.File("storage", "configs", "config.json"),
|
||||||
|
PathBuilder.File(cachePath, "config.json"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Saving all storage items needed to restore the panel
|
||||||
|
//
|
||||||
|
|
||||||
|
Logger.Info("Saving resources");
|
||||||
|
CopyDirectory(
|
||||||
|
PathBuilder.Dir("storage", "resources"),
|
||||||
|
PathBuilder.Dir(cachePath, "resources"));
|
||||||
|
|
||||||
|
Logger.Info("Saving logs");
|
||||||
|
CopyDirectory(
|
||||||
|
PathBuilder.Dir("storage", "logs"),
|
||||||
|
PathBuilder.Dir(cachePath, "logs"));
|
||||||
|
|
||||||
|
Logger.Info("Saving uploads");
|
||||||
|
CopyDirectory(
|
||||||
|
PathBuilder.Dir("storage", "uploads"),
|
||||||
|
PathBuilder.Dir(cachePath, "uploads"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Compressing the backup to a single file
|
||||||
|
//
|
||||||
|
|
||||||
|
Logger.Info("Compressing");
|
||||||
|
ZipFile.CreateFromDirectory(cachePath,
|
||||||
|
path,
|
||||||
|
CompressionLevel.Fastest,
|
||||||
|
false);
|
||||||
|
|
||||||
|
Directory.Delete(cachePath, true);
|
||||||
|
|
||||||
|
stopWatch.Stop();
|
||||||
|
Logger.Info($"Backup successfully created. Took {stopWatch.Elapsed.TotalSeconds} seconds");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CopyDirectory(string sourceDirName, string destDirName, bool copySubDirs = true)
|
||||||
|
{
|
||||||
|
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
|
||||||
|
|
||||||
|
if (!dir.Exists)
|
||||||
|
{
|
||||||
|
throw new DirectoryNotFoundException($"Source directory does not exist or could not be found: {sourceDirName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(destDirName))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(destDirName);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileInfo[] files = dir.GetFiles();
|
||||||
|
|
||||||
|
foreach (FileInfo file in files)
|
||||||
|
{
|
||||||
|
string tempPath = Path.Combine(destDirName, file.Name);
|
||||||
|
file.CopyTo(tempPath, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copySubDirs)
|
||||||
|
{
|
||||||
|
DirectoryInfo[] dirs = dir.GetDirectories();
|
||||||
|
|
||||||
|
foreach (DirectoryInfo subdir in dirs)
|
||||||
|
{
|
||||||
|
string tempPath = Path.Combine(destDirName, subdir.Name);
|
||||||
|
CopyDirectory(subdir.FullName, tempPath, copySubDirs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
88
Moonlight/App/Helpers/BitHelper.cs
Normal file
88
Moonlight/App/Helpers/BitHelper.cs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public class BitHelper
|
||||||
|
{
|
||||||
|
public static bool ReadBit(byte[] byteArray, int bitIndex)
|
||||||
|
{
|
||||||
|
if (bitIndex < 0)
|
||||||
|
throw new ArgumentOutOfRangeException("bitIndex");
|
||||||
|
|
||||||
|
int byteIndex = bitIndex / 8;
|
||||||
|
if (byteIndex >= byteArray.Length)
|
||||||
|
throw new ArgumentOutOfRangeException("bitIndex");
|
||||||
|
|
||||||
|
int bitNumber = bitIndex % 8;
|
||||||
|
byte mask = (byte)(1 << bitNumber);
|
||||||
|
|
||||||
|
return (byteArray[byteIndex] & mask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] WriteBit(byte[] byteArray, int bitIndex, bool value)
|
||||||
|
{
|
||||||
|
if (bitIndex < 0)
|
||||||
|
throw new ArgumentOutOfRangeException("bitIndex");
|
||||||
|
|
||||||
|
int byteIndex = bitIndex / 8;
|
||||||
|
byte[] resultArray;
|
||||||
|
|
||||||
|
if (byteIndex >= byteArray.Length)
|
||||||
|
{
|
||||||
|
// Create a new array with increased size and copy elements from old array
|
||||||
|
resultArray = new byte[byteIndex + 1];
|
||||||
|
Array.Copy(byteArray, resultArray, byteArray.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create a new array and copy elements from old array
|
||||||
|
resultArray = new byte[byteArray.Length];
|
||||||
|
Array.Copy(byteArray, resultArray, byteArray.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bitNumber = bitIndex % 8;
|
||||||
|
byte mask = (byte)(1 << bitNumber);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
resultArray[byteIndex] |= mask; // Set the bit to 1
|
||||||
|
else
|
||||||
|
resultArray[byteIndex] &= (byte)~mask; // Set the bit to 0
|
||||||
|
|
||||||
|
return resultArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] OverwriteByteArrays(byte[] targetArray, byte[] overwriteArray)
|
||||||
|
{
|
||||||
|
int targetLength = targetArray.Length;
|
||||||
|
int overwriteLength = overwriteArray.Length;
|
||||||
|
|
||||||
|
int maxLength = Math.Max(targetLength, overwriteLength);
|
||||||
|
|
||||||
|
byte[] resultArray = new byte[maxLength];
|
||||||
|
|
||||||
|
for (int i = 0; i < maxLength; i++)
|
||||||
|
{
|
||||||
|
byte targetByte = i < targetLength ? targetArray[i] : (byte)0;
|
||||||
|
byte overwriteByte = i < overwriteLength ? overwriteArray[i] : (byte)0;
|
||||||
|
|
||||||
|
for (int j = 0; j < 8; j++)
|
||||||
|
{
|
||||||
|
bool overwriteBit = (overwriteByte & (1 << j)) != 0;
|
||||||
|
if (i < targetLength)
|
||||||
|
{
|
||||||
|
bool targetBit = (targetByte & (1 << j)) != 0;
|
||||||
|
if (overwriteBit)
|
||||||
|
{
|
||||||
|
targetByte = targetBit ? (byte)(targetByte | (1 << j)) : (byte)(targetByte & ~(1 << j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (overwriteBit)
|
||||||
|
{
|
||||||
|
targetByte |= (byte)(1 << j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultArray[i] = targetByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
Moonlight/App/Helpers/BlurAttribute.cs
Normal file
6
Moonlight/App/Helpers/BlurAttribute.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public class BlurAttribute : Attribute
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
56
Moonlight/App/Helpers/ByteSizeValue.cs
Normal file
56
Moonlight/App/Helpers/ByteSizeValue.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public class ByteSizeValue
|
||||||
|
{
|
||||||
|
public long Bytes { get; set; }
|
||||||
|
|
||||||
|
public long KiloBytes
|
||||||
|
{
|
||||||
|
get => Bytes / 1024;
|
||||||
|
set => Bytes = value * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long MegaBytes
|
||||||
|
{
|
||||||
|
get => KiloBytes / 1024;
|
||||||
|
set => KiloBytes = value * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long GigaBytes
|
||||||
|
{
|
||||||
|
get => MegaBytes / 1024;
|
||||||
|
set => MegaBytes = value * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteSizeValue FromBytes(long bytes)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
Bytes = bytes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteSizeValue FromKiloBytes(long kiloBytes)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
KiloBytes = kiloBytes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteSizeValue FromMegaBytes(long megaBytes)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
MegaBytes = megaBytes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteSizeValue FromGigaBytes(long gigaBytes)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
GigaBytes = gigaBytes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,252 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using Logging.Net;
|
|
||||||
using Logging.Net.Loggers.SB;
|
|
||||||
using Moonlight.App.Models.Misc;
|
|
||||||
using ILogger = Logging.Net.ILogger;
|
|
||||||
|
|
||||||
namespace Moonlight.App.Helpers;
|
|
||||||
|
|
||||||
public class CacheLogger : ILogger
|
|
||||||
{
|
|
||||||
private SBLogger SbLogger = new();
|
|
||||||
private List<LogEntry> Messages = new();
|
|
||||||
|
|
||||||
public LogEntry[] GetMessages()
|
|
||||||
{
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
var result = new LogEntry[Messages.Count];
|
|
||||||
Messages.CopyTo(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear(int messages)
|
|
||||||
{
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
Messages.RemoveRange(0, Math.Min(messages, Messages.Count));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Info(string? s)
|
|
||||||
{
|
|
||||||
if (s == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
Messages.Add(new()
|
|
||||||
{
|
|
||||||
Level = "info",
|
|
||||||
Message = s
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SbLogger.Info(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Debug(string? s)
|
|
||||||
{
|
|
||||||
if (s == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
Messages.Add(new()
|
|
||||||
{
|
|
||||||
Level = "debug",
|
|
||||||
Message = s
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SbLogger.Debug(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Warn(string? s)
|
|
||||||
{
|
|
||||||
if (s == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
Messages.Add(new()
|
|
||||||
{
|
|
||||||
Level = "warn",
|
|
||||||
Message = s
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SbLogger.Warn(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Error(string? s)
|
|
||||||
{
|
|
||||||
if (s == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
Messages.Add(new()
|
|
||||||
{
|
|
||||||
Level = "error",
|
|
||||||
Message = s
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SbLogger.Error(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Fatal(string? s)
|
|
||||||
{
|
|
||||||
if (s == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
Messages.Add(new()
|
|
||||||
{
|
|
||||||
Level = "fatal",
|
|
||||||
Message = s
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SbLogger.Fatal(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InfoEx(Exception ex)
|
|
||||||
{
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
Messages.Add(new()
|
|
||||||
{
|
|
||||||
Level = "info",
|
|
||||||
Message = ex.ToStringDemystified()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SbLogger.InfoEx(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DebugEx(Exception ex)
|
|
||||||
{
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
Messages.Add(new()
|
|
||||||
{
|
|
||||||
Level = "debug",
|
|
||||||
Message = ex.ToStringDemystified()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SbLogger.DebugEx(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WarnEx(Exception ex)
|
|
||||||
{
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
Messages.Add(new()
|
|
||||||
{
|
|
||||||
Level = "warn",
|
|
||||||
Message = ex.ToStringDemystified()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SbLogger.WarnEx(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ErrorEx(Exception ex)
|
|
||||||
{
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
Messages.Add(new()
|
|
||||||
{
|
|
||||||
Level = "error",
|
|
||||||
Message = ex.ToStringDemystified()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SbLogger.ErrorEx(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FatalEx(Exception ex)
|
|
||||||
{
|
|
||||||
lock (Messages)
|
|
||||||
{
|
|
||||||
Messages.Add(new()
|
|
||||||
{
|
|
||||||
Level = "fatal",
|
|
||||||
Message = ex.ToStringDemystified()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SbLogger.FatalEx(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoggingConfiguration GetErrorConfiguration()
|
|
||||||
{
|
|
||||||
return SbLogger.GetErrorConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetErrorConfiguration(LoggingConfiguration configuration)
|
|
||||||
{
|
|
||||||
SbLogger.SetErrorConfiguration(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoggingConfiguration GetFatalConfiguration()
|
|
||||||
{
|
|
||||||
return SbLogger.GetFatalConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetFatalConfiguration(LoggingConfiguration configuration)
|
|
||||||
{
|
|
||||||
SbLogger.SetFatalConfiguration(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoggingConfiguration GetWarnConfiguration()
|
|
||||||
{
|
|
||||||
return SbLogger.GetWarnConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetWarnConfiguration(LoggingConfiguration configuration)
|
|
||||||
{
|
|
||||||
SbLogger.SetWarnConfiguration(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoggingConfiguration GetInfoConfiguration()
|
|
||||||
{
|
|
||||||
return SbLogger.GetInfoConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetInfoConfiguration(LoggingConfiguration configuration)
|
|
||||||
{
|
|
||||||
SbLogger.SetInfoConfiguration(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoggingConfiguration GetDebugConfiguration()
|
|
||||||
{
|
|
||||||
return SbLogger.GetDebugConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetDebugConfiguration(LoggingConfiguration configuration)
|
|
||||||
{
|
|
||||||
SbLogger.SetDebugConfiguration(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ILoggingAddition GetAddition()
|
|
||||||
{
|
|
||||||
return SbLogger.GetAddition();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetAddition(ILoggingAddition addition)
|
|
||||||
{
|
|
||||||
SbLogger.SetAddition(addition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool LogCallingClass
|
|
||||||
{
|
|
||||||
get => SbLogger.LogCallingClass;
|
|
||||||
set => SbLogger.LogCallingClass = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
12
Moonlight/App/Helpers/ComponentHelper.cs
Normal file
12
Moonlight/App/Helpers/ComponentHelper.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public class ComponentHelper
|
||||||
|
{
|
||||||
|
public static RenderFragment FromType(Type type) => builder =>
|
||||||
|
{
|
||||||
|
builder.OpenComponent(0, type);
|
||||||
|
builder.CloseComponent();
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Logging.Net;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Moonlight.App.Database;
|
using Moonlight.App.Database;
|
||||||
using Moonlight.App.Services;
|
using Moonlight.App.Services;
|
||||||
@@ -45,8 +44,19 @@ public class DatabaseCheckupService
|
|||||||
if (migrations.Any())
|
if (migrations.Any())
|
||||||
{
|
{
|
||||||
Logger.Info($"{migrations.Length} migrations pending. Updating now");
|
Logger.Info($"{migrations.Length} migrations pending. Updating now");
|
||||||
|
|
||||||
await BackupDatabase();
|
try
|
||||||
|
{
|
||||||
|
var backupHelper = new BackupHelper();
|
||||||
|
await backupHelper.CreateBackup(
|
||||||
|
PathBuilder.File("storage", "backups", $"{new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds()}.zip"));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Fatal("Unable to create backup");
|
||||||
|
Logger.Fatal(e);
|
||||||
|
Logger.Fatal("Moonlight will continue to start and apply the migrations without a backup");
|
||||||
|
}
|
||||||
|
|
||||||
Logger.Info("Applying migrations");
|
Logger.Info("Applying migrations");
|
||||||
|
|
||||||
@@ -59,42 +69,4 @@ public class DatabaseCheckupService
|
|||||||
Logger.Info("Database is up-to-date. No migrations have been performed");
|
Logger.Info("Database is up-to-date. No migrations have been performed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task BackupDatabase()
|
|
||||||
{
|
|
||||||
Logger.Info("Creating backup from database");
|
|
||||||
|
|
||||||
var configService = new ConfigService(new StorageService());
|
|
||||||
var dateTimeService = new DateTimeService();
|
|
||||||
|
|
||||||
var config = configService
|
|
||||||
.GetSection("Moonlight")
|
|
||||||
.GetSection("Database");
|
|
||||||
|
|
||||||
var connectionString = $"host={config.GetValue<string>("Host")};" +
|
|
||||||
$"port={config.GetValue<int>("Port")};" +
|
|
||||||
$"database={config.GetValue<string>("Database")};" +
|
|
||||||
$"uid={config.GetValue<string>("Username")};" +
|
|
||||||
$"pwd={config.GetValue<string>("Password")}";
|
|
||||||
|
|
||||||
string file = PathBuilder.File("storage", "backups", $"{dateTimeService.GetCurrentUnix()}-mysql.sql");
|
|
||||||
|
|
||||||
Logger.Info($"Saving it to: {file}");
|
|
||||||
Logger.Info("Starting backup...");
|
|
||||||
|
|
||||||
var sw = new Stopwatch();
|
|
||||||
sw.Start();
|
|
||||||
|
|
||||||
await using MySqlConnection conn = new MySqlConnection(connectionString);
|
|
||||||
await using MySqlCommand cmd = new MySqlCommand();
|
|
||||||
using MySqlBackup mb = new MySqlBackup(cmd);
|
|
||||||
|
|
||||||
cmd.Connection = conn;
|
|
||||||
await conn.OpenAsync();
|
|
||||||
mb.ExportToFile(file);
|
|
||||||
await conn.CloseAsync();
|
|
||||||
|
|
||||||
sw.Stop();
|
|
||||||
Logger.Info($"Done. {sw.Elapsed.TotalSeconds}s");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
71
Moonlight/App/Helpers/EggConverter.cs
Normal file
71
Moonlight/App/Helpers/EggConverter.cs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public static class EggConverter
|
||||||
|
{
|
||||||
|
public static Image Convert(string json)
|
||||||
|
{
|
||||||
|
var result = new Image();
|
||||||
|
|
||||||
|
var data = new ConfigurationBuilder().AddJsonStream(
|
||||||
|
new MemoryStream(Encoding.ASCII.GetBytes(json))
|
||||||
|
).Build();
|
||||||
|
|
||||||
|
result.Allocations = 1;
|
||||||
|
result.Description = data.GetValue<string>("description") ?? "";
|
||||||
|
result.Uuid = Guid.NewGuid();
|
||||||
|
result.Startup = data.GetValue<string>("startup") ?? "";
|
||||||
|
result.Name = data.GetValue<string>("name") ?? "Ptero Egg";
|
||||||
|
|
||||||
|
foreach (var variable in data.GetSection("variables").GetChildren())
|
||||||
|
{
|
||||||
|
result.Variables.Add(new()
|
||||||
|
{
|
||||||
|
Key = variable.GetValue<string>("env_variable") ?? "",
|
||||||
|
DefaultValue = variable.GetValue<string>("default_value") ?? ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var configData = data.GetSection("config");
|
||||||
|
|
||||||
|
result.ConfigFiles = configData.GetValue<string>("files") ?? "{}";
|
||||||
|
|
||||||
|
var dImagesData = JObject.Parse(json);
|
||||||
|
var dImages = (JObject)dImagesData["docker_images"]!;
|
||||||
|
|
||||||
|
foreach (var dockerImage in dImages)
|
||||||
|
{
|
||||||
|
var di = new DockerImage()
|
||||||
|
{
|
||||||
|
Default = dockerImage.Key == dImages.Properties().Last().Name,
|
||||||
|
Name = dockerImage.Value!.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
result.DockerImages.Add(di);
|
||||||
|
}
|
||||||
|
|
||||||
|
var installSection = data.GetSection("scripts").GetSection("installation");
|
||||||
|
|
||||||
|
result.InstallEntrypoint = installSection.GetValue<string>("entrypoint") ?? "bash";
|
||||||
|
result.InstallScript = installSection.GetValue<string>("script") ?? "";
|
||||||
|
result.InstallDockerImage = installSection.GetValue<string>("container") ?? "";
|
||||||
|
|
||||||
|
var rawJson = configData.GetValue<string>("startup");
|
||||||
|
|
||||||
|
var startupData = new ConfigurationBuilder().AddJsonStream(
|
||||||
|
new MemoryStream(Encoding.ASCII.GetBytes(rawJson!))
|
||||||
|
).Build();
|
||||||
|
|
||||||
|
result.StartupDetection = startupData.GetValue<string>("done", "") ?? "";
|
||||||
|
result.StopCommand = configData.GetValue<string>("stop") ?? "";
|
||||||
|
|
||||||
|
result.TagsJson = "[]";
|
||||||
|
result.BackgroundImageUrl = "";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Logging.Net;
|
using Renci.SshNet;
|
||||||
using Renci.SshNet;
|
|
||||||
using ConnectionInfo = Renci.SshNet.ConnectionInfo;
|
using ConnectionInfo = Renci.SshNet.ConnectionInfo;
|
||||||
|
|
||||||
namespace Moonlight.App.Helpers.Files;
|
namespace Moonlight.App.Helpers.Files;
|
||||||
|
|||||||
@@ -43,19 +43,22 @@ public class WingsFileAccess : FileAccess
|
|||||||
$"api/servers/{Server.Uuid}/files/list-directory?directory={CurrentPath}"
|
$"api/servers/{Server.Uuid}/files/list-directory?directory={CurrentPath}"
|
||||||
);
|
);
|
||||||
|
|
||||||
var x = new List<FileData>();
|
var result = new List<FileData>();
|
||||||
|
|
||||||
foreach (var response in res)
|
foreach (var resGrouped in res.GroupBy(x => x.Directory))
|
||||||
{
|
{
|
||||||
x.Add(new()
|
foreach (var resItem in resGrouped.OrderBy(x => x.Name))
|
||||||
{
|
{
|
||||||
Name = response.Name,
|
result.Add(new()
|
||||||
Size = response.File ? response.Size : 0,
|
{
|
||||||
IsFile = response.File,
|
Name = resItem.Name,
|
||||||
});
|
Size = resItem.File ? resItem.Size : 0,
|
||||||
|
IsFile = resItem.File,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return x.ToArray();
|
return result.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task Cd(string dir)
|
public override Task Cd(string dir)
|
||||||
@@ -111,7 +114,7 @@ public class WingsFileAccess : FileAccess
|
|||||||
request.AddParameter("name", "files");
|
request.AddParameter("name", "files");
|
||||||
request.AddParameter("filename", name);
|
request.AddParameter("filename", name);
|
||||||
request.AddHeader("Content-Type", "multipart/form-data");
|
request.AddHeader("Content-Type", "multipart/form-data");
|
||||||
request.AddHeader("Origin", ConfigService.GetSection("Moonlight").GetValue<string>("AppUrl"));
|
request.AddHeader("Origin", ConfigService.Get().Moonlight.AppUrl);
|
||||||
request.AddFile("files", () =>
|
request.AddFile("files", () =>
|
||||||
{
|
{
|
||||||
return new StreamProgressHelper(dataStream)
|
return new StreamProgressHelper(dataStream)
|
||||||
|
|||||||
@@ -1,9 +1,37 @@
|
|||||||
using Moonlight.App.Services;
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
|
||||||
namespace Moonlight.App.Helpers;
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
public static class Formatter
|
public static class Formatter
|
||||||
{
|
{
|
||||||
|
public static string ReplaceEnd(string input, string substringToReplace, string newSubstring)
|
||||||
|
{
|
||||||
|
int lastIndexOfSubstring = input.LastIndexOf(substringToReplace);
|
||||||
|
if (lastIndexOfSubstring >= 0)
|
||||||
|
{
|
||||||
|
input = input.Remove(lastIndexOfSubstring, substringToReplace.Length).Insert(lastIndexOfSubstring, newSubstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
public static string ConvertCamelCaseToSpaces(string input)
|
||||||
|
{
|
||||||
|
StringBuilder output = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (char c in input)
|
||||||
|
{
|
||||||
|
if (char.IsUpper(c))
|
||||||
|
{
|
||||||
|
output.Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
output.Append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.ToString().Trim();
|
||||||
|
}
|
||||||
public static string FormatUptime(double uptime)
|
public static string FormatUptime(double uptime)
|
||||||
{
|
{
|
||||||
TimeSpan t = TimeSpan.FromMilliseconds(uptime);
|
TimeSpan t = TimeSpan.FromMilliseconds(uptime);
|
||||||
@@ -17,6 +45,18 @@ public static class Formatter
|
|||||||
return $"{t.Hours}h {t.Minutes}m {t.Seconds}s";
|
return $"{t.Hours}h {t.Minutes}m {t.Seconds}s";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string FormatUptime(TimeSpan t)
|
||||||
|
{
|
||||||
|
if (t.Days > 0)
|
||||||
|
{
|
||||||
|
return $"{t.Days}d {t.Hours}h {t.Minutes}m {t.Seconds}s";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $"{t.Hours}h {t.Minutes}m {t.Seconds}s";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static double Round(this double d, int decimals)
|
private static double Round(this double d, int decimals)
|
||||||
{
|
{
|
||||||
@@ -116,4 +156,48 @@ public static class Formatter
|
|||||||
return (i / (1024D * 1024D)).Round(2) + " GB";
|
return (i / (1024D * 1024D)).Round(2) + " GB";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double CalculateAverage(List<double> values)
|
||||||
|
{
|
||||||
|
if (values == null || values.Count == 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("The list cannot be null or empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
double sum = 0;
|
||||||
|
foreach (double value in values)
|
||||||
|
{
|
||||||
|
sum += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum / values.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double CalculatePercentage(double part, double total)
|
||||||
|
{
|
||||||
|
if (total == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (part / total) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RenderFragment FormatLineBreaks(string content)
|
||||||
|
{
|
||||||
|
return builder =>
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
var arr = content.Split("\n", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||||
|
|
||||||
|
foreach (var line in arr)
|
||||||
|
{
|
||||||
|
builder.AddContent(i, line);
|
||||||
|
if (i++ != arr.Length - 1)
|
||||||
|
{
|
||||||
|
builder.AddMarkupContent(i, "<br/>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Logging.Net;
|
|
||||||
|
|
||||||
namespace Moonlight.App.Helpers;
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
|||||||
171
Moonlight/App/Helpers/Logger.cs
Normal file
171
Moonlight/App/Helpers/Logger.cs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
using Moonlight.App.Services.Files;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public static class Logger
|
||||||
|
{
|
||||||
|
// The private static instance of the config service, because we have no di here
|
||||||
|
private static ConfigService ConfigService = new(new StorageService());
|
||||||
|
|
||||||
|
#region String method calls
|
||||||
|
public static void Verbose(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Verbose("{Message}", message);
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Info(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Information("{Message}", message);
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Debug(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Debug("{Message}", message);
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Error(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Error("{Message}", message);
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Warn(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Warning("{Message}", message);
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fatal(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Fatal("{Message}", message);
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(message);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Exception method calls
|
||||||
|
public static void Verbose(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Verbose(exception, "");
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Info(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Information(exception, "");
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Debug(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Debug(exception, "");
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Error(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Error(exception, "");
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Warn(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Warning(exception, "");
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fatal(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Fatal(exception, "");
|
||||||
|
|
||||||
|
if(channel == "security")
|
||||||
|
LogSecurityInDb(exception);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private static string GetNameOfCallingClass(int skipFrames = 4)
|
||||||
|
{
|
||||||
|
string fullName;
|
||||||
|
Type declaringType;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
MethodBase method = new StackFrame(skipFrames, false).GetMethod();
|
||||||
|
declaringType = method.DeclaringType;
|
||||||
|
if (declaringType == null)
|
||||||
|
{
|
||||||
|
return method.Name;
|
||||||
|
}
|
||||||
|
skipFrames++;
|
||||||
|
if (declaringType.Name.Contains("<"))
|
||||||
|
fullName = declaringType.ReflectedType.Name;
|
||||||
|
else
|
||||||
|
fullName = declaringType.Name;
|
||||||
|
}
|
||||||
|
while (declaringType.Module.Name.Equals("mscorlib.dll", StringComparison.OrdinalIgnoreCase) | fullName.Contains("Logger"));
|
||||||
|
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void LogSecurityInDb(Exception exception)
|
||||||
|
{
|
||||||
|
LogSecurityInDb(exception.ToStringDemystified());
|
||||||
|
}
|
||||||
|
private static void LogSecurityInDb(string text)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var dataContext = new DataContext(ConfigService);
|
||||||
|
|
||||||
|
dataContext.SecurityLogs.Add(new()
|
||||||
|
{
|
||||||
|
Text = text
|
||||||
|
});
|
||||||
|
|
||||||
|
dataContext.SaveChanges();
|
||||||
|
dataContext.Dispose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Logging.Net;
|
|
||||||
|
|
||||||
namespace Moonlight.App.Helpers;
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using Logging.Net;
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
namespace Moonlight.App.Helpers;
|
|
||||||
|
|
||||||
public static class ParseHelper
|
public static class ParseHelper
|
||||||
{
|
{
|
||||||
|
|||||||
51
Moonlight/App/Helpers/PropBinder.cs
Normal file
51
Moonlight/App/Helpers/PropBinder.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public class PropBinder
|
||||||
|
{
|
||||||
|
private PropertyInfo PropertyInfo;
|
||||||
|
private object DataObject;
|
||||||
|
|
||||||
|
public PropBinder(PropertyInfo propertyInfo, object dataObject)
|
||||||
|
{
|
||||||
|
PropertyInfo = propertyInfo;
|
||||||
|
DataObject = dataObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StringValue
|
||||||
|
{
|
||||||
|
get => (string)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IntValue
|
||||||
|
{
|
||||||
|
get => (int)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long LongValue
|
||||||
|
{
|
||||||
|
get => (long)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool BoolValue
|
||||||
|
{
|
||||||
|
get => (bool)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime DateTimeValue
|
||||||
|
{
|
||||||
|
get => (DateTime)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double DoubleValue
|
||||||
|
{
|
||||||
|
get => (double)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
66
Moonlight/App/Helpers/Retry.cs
Normal file
66
Moonlight/App/Helpers/Retry.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public class Retry
|
||||||
|
{
|
||||||
|
private List<Type> RetryExceptionTypes;
|
||||||
|
private List<Func<Exception, bool>> RetryFilters;
|
||||||
|
private int RetryTimes = 1;
|
||||||
|
|
||||||
|
public Retry()
|
||||||
|
{
|
||||||
|
RetryExceptionTypes = new();
|
||||||
|
RetryFilters = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Retry Times(int times)
|
||||||
|
{
|
||||||
|
RetryTimes = times;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Retry At(Func<Exception, bool> filter)
|
||||||
|
{
|
||||||
|
RetryFilters.Add(filter);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Retry At<T>()
|
||||||
|
{
|
||||||
|
RetryExceptionTypes.Add(typeof(T));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Call(Func<Task> method)
|
||||||
|
{
|
||||||
|
int triesLeft = RetryTimes;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await method.Invoke();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if(triesLeft < 1) // Throw if no tries left
|
||||||
|
throw;
|
||||||
|
|
||||||
|
if (RetryExceptionTypes.Any(x => x.FullName == e.GetType().FullName))
|
||||||
|
{
|
||||||
|
triesLeft--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RetryFilters.Any(x => x.Invoke(e)))
|
||||||
|
{
|
||||||
|
triesLeft--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw if not filtered -> unknown/unhandled
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
} while (triesLeft >= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,4 +43,15 @@ public static class StringHelper
|
|||||||
|
|
||||||
return firstChar + restOfString;
|
return firstChar + restOfString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string CutInHalf(string input)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(input))
|
||||||
|
return input;
|
||||||
|
|
||||||
|
int length = input.Length;
|
||||||
|
int halfLength = length / 2;
|
||||||
|
|
||||||
|
return input.Substring(0, halfLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Logging.Net;
|
|
||||||
using Moonlight.App.Helpers.Wings.Data;
|
using Moonlight.App.Helpers.Wings.Data;
|
||||||
using Moonlight.App.Helpers.Wings.Enums;
|
using Moonlight.App.Helpers.Wings.Enums;
|
||||||
using Moonlight.App.Helpers.Wings.Events;
|
using Moonlight.App.Helpers.Wings.Events;
|
||||||
@@ -142,18 +141,28 @@ public class WingsConsole : IDisposable
|
|||||||
switch (eventData.Event)
|
switch (eventData.Event)
|
||||||
{
|
{
|
||||||
case "jwt error":
|
case "jwt error":
|
||||||
await WebSocket.CloseAsync(WebSocketCloseStatus.Empty, "Jwt error detected",
|
if (WebSocket != null)
|
||||||
CancellationToken.None);
|
{
|
||||||
|
if (WebSocket.State == WebSocketState.Connecting || WebSocket.State == WebSocketState.Open)
|
||||||
|
await WebSocket.CloseAsync(WebSocketCloseStatus.Empty, null, CancellationToken.None);
|
||||||
|
|
||||||
|
WebSocket.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
await UpdateServerState(ServerState.Offline);
|
await UpdateServerState(ServerState.Offline);
|
||||||
await UpdateConsoleState(ConsoleState.Disconnected);
|
await UpdateConsoleState(ConsoleState.Disconnected);
|
||||||
|
|
||||||
await SaveMessage("Received a jwt error", true);
|
await SaveMessage("Received a jwt error. Disconnected", true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "token expired":
|
case "token expired":
|
||||||
await WebSocket.CloseAsync(WebSocketCloseStatus.Empty, "Jwt error detected",
|
if (WebSocket != null)
|
||||||
CancellationToken.None);
|
{
|
||||||
|
if (WebSocket.State == WebSocketState.Connecting || WebSocket.State == WebSocketState.Open)
|
||||||
|
await WebSocket.CloseAsync(WebSocketCloseStatus.Empty, null, CancellationToken.None);
|
||||||
|
|
||||||
|
WebSocket.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
await UpdateServerState(ServerState.Offline);
|
await UpdateServerState(ServerState.Offline);
|
||||||
await UpdateConsoleState(ConsoleState.Disconnected);
|
await UpdateConsoleState(ConsoleState.Disconnected);
|
||||||
@@ -209,6 +218,16 @@ public class WingsConsole : IDisposable
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "install output":
|
case "install output":
|
||||||
|
if (ServerState != ServerState.Installing)
|
||||||
|
{
|
||||||
|
// Because wings is sending "install output" events BEFORE
|
||||||
|
// sending the "install started" event,
|
||||||
|
// we need to set the install state here
|
||||||
|
// See https://github.com/pterodactyl/panel/issues/4853
|
||||||
|
// for more details
|
||||||
|
await UpdateServerState(ServerState.Installing);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var line in eventData.Args)
|
foreach (var line in eventData.Args)
|
||||||
{
|
{
|
||||||
await SaveMessage(line);
|
await SaveMessage(line);
|
||||||
@@ -233,6 +252,8 @@ public class WingsConsole : IDisposable
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch(JsonReaderException){}
|
||||||
|
catch(JsonSerializationException){}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (!Disconnecting)
|
if (!Disconnecting)
|
||||||
@@ -346,6 +367,7 @@ public class WingsConsole : IDisposable
|
|||||||
public async Task Disconnect()
|
public async Task Disconnect()
|
||||||
{
|
{
|
||||||
Disconnecting = true;
|
Disconnecting = true;
|
||||||
|
Messages.Clear();
|
||||||
|
|
||||||
if (WebSocket != null)
|
if (WebSocket != null)
|
||||||
{
|
{
|
||||||
@@ -362,6 +384,7 @@ public class WingsConsole : IDisposable
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Disconnecting = true;
|
Disconnecting = true;
|
||||||
|
Messages.Clear();
|
||||||
|
|
||||||
if (WebSocket != null)
|
if (WebSocket != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class WingsConsoleHelper
|
|||||||
{
|
{
|
||||||
ServerRepository = serverRepository;
|
ServerRepository = serverRepository;
|
||||||
|
|
||||||
AppUrl = configService.GetSection("Moonlight").GetValue<string>("AppUrl");
|
AppUrl = configService.Get().Moonlight.AppUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ConnectWings(WingsConsole console, Server server)
|
public async Task ConnectWings(WingsConsole console, Server server)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class WingsJwtHelper
|
|||||||
{
|
{
|
||||||
ConfigService = configService;
|
ConfigService = configService;
|
||||||
|
|
||||||
AppUrl = ConfigService.GetSection("Moonlight").GetValue<string>("AppUrl");
|
AppUrl = ConfigService.Get().Moonlight.AppUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Generate(string secret, Action<Dictionary<string, string>> claimsAction)
|
public string Generate(string secret, Action<Dictionary<string, string>> claimsAction)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public class AvatarController : Controller
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var url = GravatarController.GetImageUrl(user.Email, 100);
|
var url = GravatarController.GetImageUrl(user.Email.ToLower(), 100);
|
||||||
|
|
||||||
using var client = new HttpClient();
|
using var client = new HttpClient();
|
||||||
var res = await client.GetByteArrayAsync(url);
|
var res = await client.GetByteArrayAsync(url);
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
using Moonlight.App.Services.Sessions;
|
||||||
|
using Stripe;
|
||||||
|
using Stripe.Checkout;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Http.Controllers.Api.Moonlight;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/moonlight/billing")]
|
||||||
|
public class BillingController : Controller
|
||||||
|
{
|
||||||
|
private readonly IdentityService IdentityService;
|
||||||
|
private readonly BillingService BillingService;
|
||||||
|
|
||||||
|
public BillingController(
|
||||||
|
IdentityService identityService,
|
||||||
|
BillingService billingService)
|
||||||
|
{
|
||||||
|
IdentityService = identityService;
|
||||||
|
BillingService = billingService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("cancel")]
|
||||||
|
public async Task<ActionResult> Cancel()
|
||||||
|
{
|
||||||
|
var user = IdentityService.User;
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
return Redirect("/login");
|
||||||
|
|
||||||
|
return Redirect("/profile/subscriptions/close");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("success")]
|
||||||
|
public async Task<ActionResult> Success()
|
||||||
|
{
|
||||||
|
var user = IdentityService.User;
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
return Redirect("/login");
|
||||||
|
|
||||||
|
await BillingService.CompleteCheckout(user);
|
||||||
|
|
||||||
|
return Redirect("/profile/subscriptions/close");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,14 +30,14 @@ public class DiscordBotController : Controller
|
|||||||
ServerService = serverService;
|
ServerService = serverService;
|
||||||
|
|
||||||
var config = configService
|
var config = configService
|
||||||
.GetSection("Moonlight")
|
.Get()
|
||||||
.GetSection("DiscordBotApi");
|
.Moonlight.DiscordBotApi;
|
||||||
|
|
||||||
Enable = config.GetValue<bool>("Enable");
|
Enable = config.Enable;
|
||||||
|
|
||||||
if (Enable)
|
if (Enable)
|
||||||
{
|
{
|
||||||
Token = config.GetValue<string>("Token");
|
Token = config.Token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ public class DiscordBotController : Controller
|
|||||||
return BadRequest();
|
return BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}/servers/{uuid}")]
|
[HttpGet("{id}/servers/{uuid}/details")]
|
||||||
public async Task<ActionResult<ServerDetails>> GetServerDetails(ulong id, Guid uuid)
|
public async Task<ActionResult<ServerDetails>> GetServerDetails(ulong id, Guid uuid)
|
||||||
{
|
{
|
||||||
if (!await IsAuth(Request))
|
if (!await IsAuth(Request))
|
||||||
@@ -123,6 +123,33 @@ public class DiscordBotController : Controller
|
|||||||
|
|
||||||
return await ServerService.GetDetails(server);
|
return await ServerService.GetDetails(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}/servers/{uuid}")]
|
||||||
|
public async Task<ActionResult<ServerDetails>> GetServer(ulong id, Guid uuid)
|
||||||
|
{
|
||||||
|
if (!await IsAuth(Request))
|
||||||
|
return StatusCode(403);
|
||||||
|
|
||||||
|
var user = await GetUserFromDiscordId(id);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
var server = ServerRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.Owner)
|
||||||
|
.Include(x => x.Image)
|
||||||
|
.Include(x => x.Node)
|
||||||
|
.FirstOrDefault(x => x.Owner.Id == user.Id && x.Uuid == uuid);
|
||||||
|
|
||||||
|
if (server == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
server.Node.Token = "";
|
||||||
|
server.Node.TokenId = "";
|
||||||
|
|
||||||
|
return Ok(server);
|
||||||
|
}
|
||||||
|
|
||||||
private Task<User?> GetUserFromDiscordId(ulong discordId)
|
private Task<User?> GetUserFromDiscordId(ulong discordId)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,145 +2,166 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
using Moonlight.App.Database.Entities.Notification;
|
using Moonlight.App.Database.Entities.Notification;
|
||||||
using Moonlight.App.Models.Notifications;
|
using Moonlight.App.Models.Notifications;
|
||||||
using Moonlight.App.Repositories;
|
using Moonlight.App.Repositories;
|
||||||
using Moonlight.App.Services;
|
using Moonlight.App.Services;
|
||||||
using Moonlight.App.Services.Notifications;
|
using Moonlight.App.Services.Notifications;
|
||||||
using Moonlight.App.Services.Sessions;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Moonlight.App.Http.Controllers.Api.Moonlight.Notifications;
|
namespace Moonlight.App.Http.Controllers.Api.Moonlight.Notifications;
|
||||||
|
|
||||||
public class ListenController : ControllerBase
|
[ApiController]
|
||||||
|
[Route("api/moonlight/notification/listen")]
|
||||||
|
public class ListenController : Controller
|
||||||
{
|
{
|
||||||
internal WebSocket ws;
|
private WebSocket WebSocket;
|
||||||
private bool active = true;
|
|
||||||
private bool isAuth = false;
|
|
||||||
private NotificationClient Client;
|
private NotificationClient Client;
|
||||||
|
private CancellationTokenSource CancellationTokenSource = new();
|
||||||
private readonly IdentityService IdentityService;
|
|
||||||
private readonly NotificationRepository NotificationRepository;
|
|
||||||
private readonly OneTimeJwtService OneTimeJwtService;
|
|
||||||
private readonly NotificationClientService NotificationClientService;
|
|
||||||
private readonly NotificationServerService NotificationServerService;
|
|
||||||
|
|
||||||
public ListenController(IdentityService identityService,
|
private User? CurrentUser;
|
||||||
NotificationRepository notificationRepository,
|
|
||||||
OneTimeJwtService oneTimeJwtService,
|
private readonly OneTimeJwtService OneTimeJwtService;
|
||||||
NotificationClientService notificationClientService,
|
private readonly NotificationServerService NotificationServerService;
|
||||||
NotificationServerService notificationServerService)
|
private readonly Repository<NotificationClient> NotificationClientRepository;
|
||||||
|
|
||||||
|
public ListenController(
|
||||||
|
OneTimeJwtService oneTimeJwtService,
|
||||||
|
NotificationServerService notificationServerService, Repository<NotificationClient> notificationClientRepository)
|
||||||
{
|
{
|
||||||
IdentityService = identityService;
|
|
||||||
NotificationRepository = notificationRepository;
|
|
||||||
OneTimeJwtService = oneTimeJwtService;
|
OneTimeJwtService = oneTimeJwtService;
|
||||||
NotificationClientService = notificationClientService;
|
|
||||||
NotificationServerService = notificationServerService;
|
NotificationServerService = notificationServerService;
|
||||||
|
NotificationClientRepository = notificationClientRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/api/moonlight/notifications/listen")]
|
[Route("/api/moonlight/notifications/listen")]
|
||||||
public async Task Get()
|
public async Task<ActionResult> Get()
|
||||||
{
|
{
|
||||||
if (HttpContext.WebSockets.IsWebSocketRequest)
|
if (HttpContext.WebSockets.IsWebSocketRequest)
|
||||||
{
|
{
|
||||||
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
|
WebSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
|
||||||
ws = webSocket;
|
|
||||||
await Echo();
|
await ProcessWebsocket();
|
||||||
|
|
||||||
|
return new EmptyResult();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
return StatusCode(400);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Echo()
|
private async Task ProcessWebsocket()
|
||||||
{
|
{
|
||||||
while (active)
|
while (!CancellationTokenSource.Token.IsCancellationRequested && WebSocket.State == WebSocketState.Open)
|
||||||
{
|
{
|
||||||
byte[] bytes = new byte[1024 * 16];
|
try
|
||||||
var asg = new ArraySegment<byte>(bytes);
|
|
||||||
var res = await ws.ReceiveAsync(asg, CancellationToken.None);
|
|
||||||
|
|
||||||
var text = Encoding.UTF8.GetString(bytes).Trim('\0');
|
|
||||||
|
|
||||||
var obj = JsonConvert.DeserializeObject<BasicWSModel>(text);
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(obj.Action))
|
|
||||||
{
|
{
|
||||||
await HandleRequest(text, obj.Action);
|
byte[] buffer = new byte[1024 * 16];
|
||||||
|
_ = await WebSocket.ReceiveAsync(buffer, CancellationTokenSource.Token);
|
||||||
|
var text = Encoding.UTF8.GetString(buffer).Trim('\0');
|
||||||
|
|
||||||
|
var basicWsModel = JsonConvert.DeserializeObject<BasicWSModel>(text) ?? new();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(basicWsModel.Action))
|
||||||
|
{
|
||||||
|
await HandleRequest(text, basicWsModel.Action);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WebSocket.State != WebSocketState.Open)
|
||||||
|
{
|
||||||
|
CancellationTokenSource.Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (WebSocketException e)
|
||||||
|
{
|
||||||
|
CancellationTokenSource.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
active = ws.State == WebSocketState.Open;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await NotificationServerService.UnRegisterClient(Client);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleRequest(string text, string action)
|
private async Task HandleRequest(string text, string action)
|
||||||
{
|
{
|
||||||
if (!isAuth && action == "login")
|
if (CurrentUser == null && action != "login")
|
||||||
await Login(text);
|
|
||||||
else if (!isAuth)
|
|
||||||
await ws.SendAsync(Encoding.UTF8.GetBytes("{\"error\": \"Unauthorised\"}"), WebSocketMessageType.Text,
|
|
||||||
WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
|
|
||||||
else switch (action)
|
|
||||||
{
|
{
|
||||||
|
await Send("{\"error\": \"Unauthorised\"}");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case "login":
|
||||||
|
await Login(text);
|
||||||
|
break;
|
||||||
case "received":
|
case "received":
|
||||||
await Received(text);
|
await Received(text);
|
||||||
break;
|
break;
|
||||||
case "read":
|
case "read":
|
||||||
await Read(text);
|
await Read(text);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task Send(string text)
|
||||||
|
{
|
||||||
|
await WebSocket.SendAsync(
|
||||||
|
Encoding.UTF8.GetBytes(text),
|
||||||
|
WebSocketMessageType.Text,
|
||||||
|
WebSocketMessageFlags.EndOfMessage, CancellationTokenSource.Token
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Login(string json)
|
private async Task Login(string json)
|
||||||
{
|
{
|
||||||
var jwt = JsonConvert.DeserializeObject<Login>(json).token;
|
var loginModel = JsonConvert.DeserializeObject<Login>(json) ?? new();
|
||||||
|
|
||||||
var dict = await OneTimeJwtService.Validate(jwt);
|
var dict = await OneTimeJwtService.Validate(loginModel.Token);
|
||||||
|
|
||||||
if (dict == null)
|
if (dict == null)
|
||||||
{
|
{
|
||||||
string error = "{\"status\":false}";
|
await Send("{\"status\":false}");
|
||||||
var bytes = Encoding.UTF8.GetBytes(error);
|
|
||||||
await ws.SendAsync(bytes, WebSocketMessageType.Text, WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var _clientId = dict["clientId"];
|
if (!int.TryParse(dict["clientId"], out int clientId))
|
||||||
var clientId = int.Parse(_clientId);
|
{
|
||||||
|
await Send("{\"status\":false}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var client = NotificationRepository.GetClients().Include(x => x.User).First(x => x.Id == clientId);
|
Client = NotificationClientRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.User)
|
||||||
|
.First(x => x.Id == clientId);
|
||||||
|
|
||||||
Client = client;
|
CurrentUser = Client.User;
|
||||||
await InitWebsocket();
|
|
||||||
|
|
||||||
string success = "{\"status\":true}";
|
|
||||||
var byt = Encoding.UTF8.GetBytes(success);
|
|
||||||
await ws.SendAsync(byt, WebSocketMessageType.Text, WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task InitWebsocket()
|
await NotificationServerService.RegisterClient(WebSocket, Client);
|
||||||
{
|
|
||||||
NotificationClientService.listenController = this;
|
|
||||||
NotificationClientService.WebsocketReady(Client);
|
|
||||||
|
|
||||||
isAuth = true;
|
await Send("{\"status\":true}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Received(string json)
|
private async Task Received(string json)
|
||||||
{
|
{
|
||||||
var id = JsonConvert.DeserializeObject<NotificationById>(json).notification;
|
var id = JsonConvert.DeserializeObject<NotificationById>(json).Notification;
|
||||||
|
|
||||||
//TODO: Implement ws notification received
|
//TODO: Implement ws notification received
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Read(string json)
|
private async Task Read(string json)
|
||||||
{
|
{
|
||||||
var id = JsonConvert.DeserializeObject<NotificationById>(json).notification;
|
var model = JsonConvert.DeserializeObject<NotificationById>(json) ?? new();
|
||||||
|
|
||||||
await NotificationServerService.SendAction(NotificationClientService.User,
|
await NotificationServerService.SendAction(
|
||||||
JsonConvert.SerializeObject(new NotificationById() {Action = "hide", notification = id}));
|
CurrentUser!,
|
||||||
|
JsonConvert.SerializeObject(
|
||||||
|
new NotificationById()
|
||||||
|
{
|
||||||
|
Action = "hide", Notification = model.Notification
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@ public class RegisterController : Controller
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult<TokenRegister>> Register()
|
public async Task<ActionResult<TokenRegister>> Register()
|
||||||
{
|
{
|
||||||
var user = await IdentityService.Get();
|
var user = IdentityService.User;
|
||||||
|
|
||||||
if (user == null)
|
if (user == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Logging.Net;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Moonlight.App.Helpers;
|
||||||
using Moonlight.App.Services;
|
using Moonlight.App.Services;
|
||||||
using Moonlight.App.Services.Sessions;
|
using Moonlight.App.Services.Sessions;
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ public class OAuth2Controller : Controller
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var currentUser = await IdentityService.Get();
|
var currentUser = IdentityService.User;
|
||||||
|
|
||||||
if (currentUser != null)
|
if (currentUser != null)
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user