Merge branch 'main' into DiscordBot
This commit is contained in:
11
Moonlight/App/Helpers/FieldCssHelper.cs
Normal file
11
Moonlight/App/Helpers/FieldCssHelper.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public class FieldCssHelper : FieldCssClassProvider
|
||||
{
|
||||
public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier)
|
||||
{
|
||||
return editContext.GetValidationMessages(fieldIdentifier).Any() ? "is-invalid" : "is-valid";
|
||||
}
|
||||
}
|
||||
8
Moonlight/App/Helpers/Files/ContextAction.cs
Normal file
8
Moonlight/App/Helpers/Files/ContextAction.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Moonlight.App.Helpers.Files;
|
||||
|
||||
public class ContextAction
|
||||
{
|
||||
public string Id { get; set; } = "";
|
||||
public string Name { get; set; } = "";
|
||||
public Action<FileData> Action { get; set; }
|
||||
}
|
||||
24
Moonlight/App/Helpers/Files/FileAccess.cs
Normal file
24
Moonlight/App/Helpers/Files/FileAccess.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Moonlight.App.Helpers.Files;
|
||||
|
||||
public abstract class FileAccess : ICloneable
|
||||
{
|
||||
public string CurrentPath { get; set; } = "/";
|
||||
|
||||
public abstract Task<FileData[]> Ls();
|
||||
public abstract Task Cd(string dir);
|
||||
public abstract Task Up();
|
||||
public abstract Task SetDir(string dir);
|
||||
public abstract Task<string> Read(FileData fileData);
|
||||
public abstract Task Write(FileData fileData, string content);
|
||||
public abstract Task Upload(string name, Stream stream, Action<int>? progressUpdated = null);
|
||||
public abstract Task MkDir(string name);
|
||||
public abstract Task<string> Pwd();
|
||||
public abstract Task<string> DownloadUrl(FileData fileData);
|
||||
public abstract Task<Stream> DownloadStream(FileData fileData);
|
||||
public abstract Task Delete(FileData fileData);
|
||||
public abstract Task Move(FileData fileData, string newPath);
|
||||
public abstract Task Compress(params FileData[] files);
|
||||
public abstract Task Decompress(FileData fileData);
|
||||
public abstract Task<string> GetLaunchUrl();
|
||||
public abstract object Clone();
|
||||
}
|
||||
8
Moonlight/App/Helpers/Files/FileData.cs
Normal file
8
Moonlight/App/Helpers/Files/FileData.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Moonlight.App.Helpers.Files;
|
||||
|
||||
public class FileData
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public long Size { get; set; }
|
||||
public bool IsFile { get; set; }
|
||||
}
|
||||
232
Moonlight/App/Helpers/Files/WingsFileAccess.cs
Normal file
232
Moonlight/App/Helpers/Files/WingsFileAccess.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
using System.Web;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Wings.Requests;
|
||||
using Moonlight.App.Models.Wings.Resources;
|
||||
using Moonlight.App.Services;
|
||||
using RestSharp;
|
||||
|
||||
namespace Moonlight.App.Helpers.Files;
|
||||
|
||||
public class WingsFileAccess : FileAccess
|
||||
{
|
||||
private readonly WingsApiHelper WingsApiHelper;
|
||||
private readonly WingsJwtHelper WingsJwtHelper;
|
||||
private readonly ConfigService ConfigService;
|
||||
private readonly Server Server;
|
||||
private readonly User User;
|
||||
|
||||
public WingsFileAccess(
|
||||
WingsApiHelper wingsApiHelper,
|
||||
WingsJwtHelper wingsJwtHelper,
|
||||
Server server,
|
||||
ConfigService configService,
|
||||
User user)
|
||||
{
|
||||
WingsApiHelper = wingsApiHelper;
|
||||
WingsJwtHelper = wingsJwtHelper;
|
||||
Server = server;
|
||||
ConfigService = configService;
|
||||
User = user;
|
||||
|
||||
if (server.Node == null)
|
||||
{
|
||||
throw new ArgumentException("The wings file access server model needs to include the node data");
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<FileData[]> Ls()
|
||||
{
|
||||
var res = await WingsApiHelper.Get<ListDirectory[]>(
|
||||
Server.Node,
|
||||
$"api/servers/{Server.Uuid}/files/list-directory?directory={CurrentPath}"
|
||||
);
|
||||
|
||||
var x = new List<FileData>();
|
||||
|
||||
foreach (var response in res)
|
||||
{
|
||||
x.Add(new()
|
||||
{
|
||||
Name = response.Name,
|
||||
Size = response.File ? response.Size : 0,
|
||||
IsFile = response.File,
|
||||
});
|
||||
}
|
||||
|
||||
return x.ToArray();
|
||||
}
|
||||
|
||||
public override Task Cd(string dir)
|
||||
{
|
||||
var x = Path.Combine(CurrentPath, dir).Replace("\\", "/") + "/";
|
||||
x = x.Replace("//", "/");
|
||||
CurrentPath = x;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override Task Up()
|
||||
{
|
||||
CurrentPath = Path.GetFullPath(Path.Combine(CurrentPath, "..")).Replace("\\", "/").Replace("C:", "");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override Task SetDir(string dir)
|
||||
{
|
||||
CurrentPath = dir;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task<string> Read(FileData fileData)
|
||||
{
|
||||
return await WingsApiHelper.GetRaw(Server.Node,
|
||||
$"api/servers/{Server.Uuid}/files/contents?file={CurrentPath}{fileData.Name}");
|
||||
}
|
||||
|
||||
public override async Task Write(FileData fileData, string content)
|
||||
{
|
||||
await WingsApiHelper.PostRaw(Server.Node,
|
||||
$"api/servers/{Server.Uuid}/files/write?file={CurrentPath}{fileData.Name}", content);
|
||||
}
|
||||
|
||||
public override async Task Upload(string name, Stream dataStream, Action<int>? progressUpdated = null)
|
||||
{
|
||||
var token = WingsJwtHelper.Generate(
|
||||
Server.Node.Token,
|
||||
claims => { claims.Add("server_uuid", Server.Uuid.ToString()); }
|
||||
);
|
||||
|
||||
var client = new RestClient();
|
||||
var request = new RestRequest();
|
||||
|
||||
if (Server.Node.Ssl)
|
||||
request.Resource =
|
||||
$"https://{Server.Node.Fqdn}:{Server.Node.HttpPort}/upload/file?token={token}&directory={CurrentPath}";
|
||||
else
|
||||
request.Resource =
|
||||
$"http://{Server.Node.Fqdn}:{Server.Node.HttpPort}/upload/file?token={token}&directory={CurrentPath}";
|
||||
|
||||
request.AddParameter("name", "files");
|
||||
request.AddParameter("filename", name);
|
||||
request.AddHeader("Content-Type", "multipart/form-data");
|
||||
request.AddHeader("Origin", ConfigService.GetSection("Moonlight").GetValue<string>("AppUrl"));
|
||||
request.AddFile("files", () =>
|
||||
{
|
||||
return new StreamProgressHelper(dataStream)
|
||||
{
|
||||
Progress = i => { progressUpdated?.Invoke(i); }
|
||||
};
|
||||
}, name);
|
||||
|
||||
await client.ExecutePostAsync(request);
|
||||
|
||||
client.Dispose();
|
||||
dataStream.Close();
|
||||
}
|
||||
|
||||
public override async Task MkDir(string name)
|
||||
{
|
||||
await WingsApiHelper.Post(Server.Node, $"api/servers/{Server.Uuid}/files/create-directory",
|
||||
new CreateDirectory()
|
||||
{
|
||||
Name = name,
|
||||
Path = CurrentPath
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public override Task<string> Pwd()
|
||||
{
|
||||
return Task.FromResult(CurrentPath);
|
||||
}
|
||||
|
||||
public override Task<string> DownloadUrl(FileData fileData)
|
||||
{
|
||||
var token = WingsJwtHelper.Generate(Server.Node.Token, claims =>
|
||||
{
|
||||
claims.Add("server_uuid", Server.Uuid.ToString());
|
||||
claims.Add("file_path", CurrentPath + "/" + fileData.Name);
|
||||
});
|
||||
|
||||
if (Server.Node.Ssl)
|
||||
{
|
||||
return Task.FromResult(
|
||||
$"https://{Server.Node.Fqdn}:{Server.Node.HttpPort}/download/file?token={token}"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Task.FromResult(
|
||||
$"http://{Server.Node.Fqdn}:{Server.Node.HttpPort}/download/file?token={token}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public override Task<Stream> DownloadStream(FileData fileData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override async Task Delete(FileData fileData)
|
||||
{
|
||||
await WingsApiHelper.Post(Server.Node, $"api/servers/{Server.Uuid}/files/delete", new DeleteFiles()
|
||||
{
|
||||
Root = CurrentPath,
|
||||
Files = new()
|
||||
{
|
||||
fileData.Name
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task Move(FileData fileData, string newPath)
|
||||
{
|
||||
var req = new RenameFiles()
|
||||
{
|
||||
Root = "/",
|
||||
Files = new[]
|
||||
{
|
||||
new RenameFilesData()
|
||||
{
|
||||
From = (CurrentPath + fileData.Name),
|
||||
To = newPath
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await WingsApiHelper.Put(Server.Node, $"api/servers/{Server.Uuid}/files/rename", req);
|
||||
}
|
||||
|
||||
public override async Task Compress(params FileData[] files)
|
||||
{
|
||||
var req = new CompressFiles()
|
||||
{
|
||||
Root = CurrentPath,
|
||||
Files = files.Select(x => x.Name).ToArray()
|
||||
};
|
||||
|
||||
await WingsApiHelper.Post(Server.Node, $"api/servers/{Server.Uuid}/files/compress", req);
|
||||
}
|
||||
|
||||
public override async Task Decompress(FileData fileData)
|
||||
{
|
||||
var req = new DecompressFile()
|
||||
{
|
||||
Root = CurrentPath,
|
||||
File = fileData.Name
|
||||
};
|
||||
|
||||
await WingsApiHelper.Post(Server.Node, $"api/servers/{Server.Uuid}/files/decompress", req);
|
||||
}
|
||||
|
||||
public override Task<string> GetLaunchUrl()
|
||||
{
|
||||
return Task.FromResult(
|
||||
$"sftp://{User.Id}.{StringHelper.IntToStringWithLeadingZeros(Server.Id, 8)}@{Server.Node.Fqdn}:{Server.Node.SftpPort}");
|
||||
}
|
||||
|
||||
public override object Clone()
|
||||
{
|
||||
return new WingsFileAccess(WingsApiHelper, WingsJwtHelper, Server, ConfigService, User);
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,11 @@ public class PaperApiHelper
|
||||
else
|
||||
requrl = ApiUrl + "/" + url;
|
||||
|
||||
RestRequest request = new(requrl);
|
||||
RestRequest request = new(requrl, Method.Get);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
|
||||
var response = await client.GetAsync(request);
|
||||
var response = await client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
|
||||
@@ -14,24 +14,13 @@ public class WingsApiHelper
|
||||
Client = new();
|
||||
}
|
||||
|
||||
private string GetApiUrl(Node node)
|
||||
{
|
||||
if(node.Ssl)
|
||||
return $"https://{node.Fqdn}:{node.HttpPort}/";
|
||||
else
|
||||
return $"http://{node.Fqdn}:{node.HttpPort}/";
|
||||
//return $"https://{node.Fqdn}:{node.HttpPort}/";
|
||||
}
|
||||
|
||||
public async Task<T> Get<T>(Node node, string resource)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Get;
|
||||
|
||||
var response = await Client.GetAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -53,13 +42,11 @@ public class WingsApiHelper
|
||||
|
||||
public async Task<string> GetRaw(Node node, string resource)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Get;
|
||||
|
||||
var response = await Client.GetAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -81,18 +68,16 @@ public class WingsApiHelper
|
||||
|
||||
public async Task<T> Post<T>(Node node, string resource, object? body)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Post;
|
||||
|
||||
request.AddParameter("text/plain",
|
||||
JsonConvert.SerializeObject(body),
|
||||
ParameterType.RequestBody
|
||||
);
|
||||
|
||||
var response = await Client.PostAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -114,16 +99,14 @@ public class WingsApiHelper
|
||||
|
||||
public async Task Post(Node node, string resource, object? body)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Post;
|
||||
|
||||
if(body != null)
|
||||
if(body != null)
|
||||
request.AddParameter("text/plain", JsonConvert.SerializeObject(body), ParameterType.RequestBody);
|
||||
|
||||
var response = await Client.PostAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -143,15 +126,13 @@ public class WingsApiHelper
|
||||
|
||||
public async Task PostRaw(Node node, string resource, object body)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Post;
|
||||
|
||||
request.AddParameter("text/plain", body, ParameterType.RequestBody);
|
||||
|
||||
var response = await Client.PostAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -171,16 +152,14 @@ public class WingsApiHelper
|
||||
|
||||
public async Task Delete(Node node, string resource, object? body)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Delete;
|
||||
|
||||
if(body != null)
|
||||
if(body != null)
|
||||
request.AddParameter("text/plain", JsonConvert.SerializeObject(body), ParameterType.RequestBody);
|
||||
|
||||
var response = await Client.DeleteAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -200,15 +179,13 @@ public class WingsApiHelper
|
||||
|
||||
public async Task Put(Node node, string resource, object? body)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Put;
|
||||
|
||||
request.AddParameter("text/plain", JsonConvert.SerializeObject(body), ParameterType.RequestBody);
|
||||
|
||||
var response = await Client.PutAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -225,4 +202,20 @@ public class WingsApiHelper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RestRequest CreateRequest(Node node, string resource)
|
||||
{
|
||||
var url = (node.Ssl ? "https" : "http") + $"://{node.Fqdn}:{node.HttpPort}/" + resource;
|
||||
|
||||
var request = new RestRequest(url)
|
||||
{
|
||||
Timeout = 60 * 15
|
||||
};
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,13 @@ public class WingsServerConverter
|
||||
wingsServer.Settings.Environment.Add(v.Key, v.Value);
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
foreach (var allocation in server.Allocations)
|
||||
{
|
||||
wingsServer.Settings.Environment.Add("ML_PORT_" + i, allocation.Port.ToString());
|
||||
i++;
|
||||
}
|
||||
|
||||
// Stop
|
||||
if (image.StopCommand.StartsWith("!"))
|
||||
|
||||
Reference in New Issue
Block a user