- add: Service think
This commit is contained in:
62
Nebula.Launcher/Services/ConfigurationService.cs
Normal file
62
Nebula.Launcher/Services/ConfigurationService.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
|
||||
public class ConVar
|
||||
{
|
||||
public string Name { get; }
|
||||
public Type Type { get; }
|
||||
public object? DefaultValue { get; }
|
||||
|
||||
private ConVar(string name, Type type, object? defaultValue)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
DefaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public static ConVar Build<T>(string name, T? defaultValue = default)
|
||||
{
|
||||
return new ConVar(name, typeof(T), defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
[ServiceRegister]
|
||||
public class ConfigurationService
|
||||
{
|
||||
public ConfigurationService()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public object? GetConfigValue(ConVar conVar)
|
||||
{
|
||||
return conVar.DefaultValue;
|
||||
}
|
||||
|
||||
public T? GetConfigValue<T>(ConVar conVar)
|
||||
{
|
||||
var value = GetConfigValue(conVar);
|
||||
if (value is not T tv) return default;
|
||||
return tv;
|
||||
}
|
||||
|
||||
public bool TryGetConfigValue(ConVar conVar,[NotNullWhen(true)] out object? value)
|
||||
{
|
||||
value = GetConfigValue(conVar);
|
||||
return value != null;
|
||||
}
|
||||
|
||||
public bool TryGetConfigValue<T>(ConVar conVar, [NotNullWhen(true)] out T? value)
|
||||
{
|
||||
value = GetConfigValue<T>(conVar);
|
||||
return value != null;
|
||||
}
|
||||
|
||||
public void SetValue(ConVar conVar, object value)
|
||||
{
|
||||
if(conVar.Type != value.GetType())
|
||||
return;
|
||||
}
|
||||
}
|
||||
70
Nebula.Launcher/Services/DebugService.cs
Normal file
70
Nebula.Launcher/Services/DebugService.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Nebula.Launcher.Services.Logging;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class DebugService : IDisposable
|
||||
{
|
||||
public ILogger Logger;
|
||||
|
||||
private static string LogPath = Path.Combine(FileService.RootPath, "log");
|
||||
public DateTime LogDate = DateTime.Now;
|
||||
private FileStream LogStream;
|
||||
private StreamWriter LogWriter;
|
||||
|
||||
public DebugService(ILogger logger)
|
||||
{
|
||||
Logger = logger;
|
||||
|
||||
if (!Directory.Exists(LogPath))
|
||||
Directory.CreateDirectory(LogPath);
|
||||
|
||||
var filename = String.Format("{0:yyyy-MM-dd}.txt", DateTime.Now);
|
||||
|
||||
LogStream = File.Open(Path.Combine(LogPath, filename),
|
||||
FileMode.Append, FileAccess.Write);
|
||||
LogWriter = new StreamWriter(LogStream);
|
||||
}
|
||||
|
||||
public void Debug(string message)
|
||||
{
|
||||
Log(LoggerCategory.Debug, message);
|
||||
}
|
||||
|
||||
public void Error(string message)
|
||||
{
|
||||
Log(LoggerCategory.Error, message);
|
||||
}
|
||||
|
||||
public void Log(string message)
|
||||
{
|
||||
Log(LoggerCategory.Log, message);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LogWriter.Dispose();
|
||||
LogStream.Dispose();
|
||||
}
|
||||
|
||||
private void Log(LoggerCategory category, string message)
|
||||
{
|
||||
Logger.Log(category, message);
|
||||
SaveToLog(category, message);
|
||||
}
|
||||
|
||||
private void SaveToLog(LoggerCategory category, string message)
|
||||
{
|
||||
LogWriter.WriteLine($"[{category}] {message}");
|
||||
LogWriter.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public enum LoggerCategory
|
||||
{
|
||||
Log,
|
||||
Debug,
|
||||
Error
|
||||
}
|
||||
64
Nebula.Launcher/Services/FileService.cs
Normal file
64
Nebula.Launcher/Services/FileService.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.InteropServices;
|
||||
using Nebula.Launcher.FileApis;
|
||||
using Nebula.Launcher.FileApis.Interfaces;
|
||||
using Nebula.Launcher.Utils;
|
||||
using Robust.LoaderApi;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
|
||||
public class FileService
|
||||
{
|
||||
public static string RootPath = Path.Join(Environment.GetFolderPath(
|
||||
Environment.SpecialFolder.ApplicationData), "./Datum/");
|
||||
|
||||
private readonly DebugService _debugService;
|
||||
public readonly IReadWriteFileApi ContentFileApi;
|
||||
|
||||
public readonly IReadWriteFileApi EngineFileApi;
|
||||
public readonly IReadWriteFileApi ManifestFileApi;
|
||||
private HashApi? _hashApi;
|
||||
|
||||
public FileService(DebugService debugService)
|
||||
{
|
||||
_debugService = debugService;
|
||||
ContentFileApi = CreateFileApi("content/");
|
||||
EngineFileApi = CreateFileApi("engine/");
|
||||
ManifestFileApi = CreateFileApi("manifest/");
|
||||
}
|
||||
|
||||
public List<RobustManifestItem> ManifestItems
|
||||
{
|
||||
set => _hashApi = new HashApi(value, ContentFileApi);
|
||||
}
|
||||
|
||||
public HashApi HashApi
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_hashApi is null) throw new Exception("Hash API is not initialized!");
|
||||
return _hashApi;
|
||||
}
|
||||
set => _hashApi = value;
|
||||
}
|
||||
|
||||
public IReadWriteFileApi CreateFileApi(string path)
|
||||
{
|
||||
return new FileApi(Path.Join(RootPath, path));
|
||||
}
|
||||
|
||||
public ZipFileApi OpenZip(string path, IFileApi fileApi)
|
||||
{
|
||||
if (!fileApi.TryOpen(path, out var zipStream))
|
||||
return null;
|
||||
|
||||
var zipArchive = new ZipArchive(zipStream, ZipArchiveMode.Read);
|
||||
|
||||
var prefix = "";
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) prefix = "Space Station 14.app/Contents/Resources/";
|
||||
return new ZipFileApi(zipArchive, prefix);
|
||||
}
|
||||
}
|
||||
76
Nebula.Launcher/Services/HubService.cs
Normal file
76
Nebula.Launcher/Services/HubService.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Threading;
|
||||
using Nebula.Launcher.Models;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class HubService
|
||||
{
|
||||
private readonly RestService _restService;
|
||||
|
||||
public Action<HubServerChangedEventArgs>? HubServerChangedEventArgs;
|
||||
|
||||
public readonly ObservableCollection<string> HubList = new();
|
||||
|
||||
private readonly Dictionary<string, List<ServerInfo>> _servers = new();
|
||||
|
||||
|
||||
public HubService(ConfigurationService configurationService, RestService restService)
|
||||
{
|
||||
_restService = restService;
|
||||
HubList.CollectionChanged += HubListCollectionChanged;
|
||||
|
||||
foreach (var hubUrl in configurationService.GetConfigValue<string[]>(CurrentConVar.Hub)!)
|
||||
{
|
||||
HubList.Add(hubUrl);
|
||||
}
|
||||
}
|
||||
|
||||
private async void HubListCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.NewItems is not null)
|
||||
{
|
||||
foreach (var hubUri in e.NewItems)
|
||||
{
|
||||
var urlStr = (string)hubUri;
|
||||
var servers = await _restService.GetAsyncDefault<List<ServerInfo>>(new Uri(urlStr), [], CancellationToken.None);
|
||||
_servers[urlStr] = servers;
|
||||
HubServerChangedEventArgs?.Invoke(new HubServerChangedEventArgs(servers, HubServerChangeAction.Add));
|
||||
}
|
||||
}
|
||||
|
||||
if (e.OldItems is not null)
|
||||
{
|
||||
foreach (var hubUri in e.OldItems)
|
||||
{
|
||||
var urlStr = (string)hubUri;
|
||||
if (_servers.TryGetValue(urlStr, out var serverInfos))
|
||||
{
|
||||
_servers.Remove(urlStr);
|
||||
HubServerChangedEventArgs?.Invoke(new HubServerChangedEventArgs(serverInfos, HubServerChangeAction.Remove));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class HubServerChangedEventArgs : EventArgs
|
||||
{
|
||||
public HubServerChangeAction Action;
|
||||
public List<ServerInfo> Items;
|
||||
|
||||
public HubServerChangedEventArgs(List<ServerInfo> items, HubServerChangeAction action)
|
||||
{
|
||||
Items = items;
|
||||
Action = action;
|
||||
}
|
||||
}
|
||||
|
||||
public enum HubServerChangeAction
|
||||
{
|
||||
Add, Remove,
|
||||
}
|
||||
15
Nebula.Launcher/Services/Logging/ConsoleLogger.cs
Normal file
15
Nebula.Launcher/Services/Logging/ConsoleLogger.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Nebula.Launcher.Services.Logging;
|
||||
|
||||
[ServiceRegister(typeof(ILogger))]
|
||||
public class ConsoleLogger : ILogger
|
||||
{
|
||||
public void Log(LoggerCategory loggerCategory, string message)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkCyan;
|
||||
Console.Write($"[{Enum.GetName(loggerCategory)}] ");
|
||||
Console.ResetColor();
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
}
|
||||
6
Nebula.Launcher/Services/Logging/ILogger.cs
Normal file
6
Nebula.Launcher/Services/Logging/ILogger.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Nebula.Launcher.Services.Logging;
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
public void Log(LoggerCategory loggerCategory, string message);
|
||||
}
|
||||
154
Nebula.Launcher/Services/RestService.cs
Normal file
154
Nebula.Launcher/Services/RestService.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nebula.Launcher.Services;
|
||||
|
||||
[ServiceRegister]
|
||||
public class RestService
|
||||
{
|
||||
private readonly HttpClient _client = new();
|
||||
private readonly DebugService _debug;
|
||||
|
||||
private readonly JsonSerializerOptions _serializerOptions = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
public RestService(DebugService debug)
|
||||
{
|
||||
_debug = debug;
|
||||
}
|
||||
|
||||
public async Task<RestResult<T>> GetAsync<T>(Uri uri, CancellationToken cancellationToken)
|
||||
{
|
||||
_debug.Debug("GET " + uri);
|
||||
try
|
||||
{
|
||||
var response = await _client.GetAsync(uri, cancellationToken);
|
||||
return await ReadResult<T>(response, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_debug.Error("ERROR WHILE CONNECTION " + uri + ": " + ex.Message);
|
||||
return new RestResult<T>(default, ex.Message, HttpStatusCode.RequestTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<T> GetAsyncDefault<T>(Uri uri, T defaultValue, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await GetAsync<T>(uri, cancellationToken);
|
||||
return result.Value ?? defaultValue;
|
||||
}
|
||||
|
||||
public async Task<RestResult<K>> PostAsync<K, T>(T information, Uri uri, CancellationToken cancellationToken)
|
||||
{
|
||||
_debug.Debug("POST " + uri);
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Serialize(information, _serializerOptions);
|
||||
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||
var response = await _client.PostAsync(uri, content, cancellationToken);
|
||||
return await ReadResult<K>(response, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_debug.Debug("ERROR " + ex.Message);
|
||||
return new RestResult<K>(default, ex.Message, HttpStatusCode.RequestTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<RestResult<T>> PostAsync<T>(Stream stream, Uri uri, CancellationToken cancellationToken)
|
||||
{
|
||||
_debug.Debug("POST " + uri);
|
||||
try
|
||||
{
|
||||
using var multipartFormContent =
|
||||
new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture));
|
||||
multipartFormContent.Add(new StreamContent(stream), "formFile", "image.png");
|
||||
var response = await _client.PostAsync(uri, multipartFormContent, cancellationToken);
|
||||
return await ReadResult<T>(response, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_debug.Error("ERROR " + ex.Message);
|
||||
if (ex.StackTrace != null) _debug.Error(ex.StackTrace);
|
||||
return new RestResult<T>(default, ex.Message, HttpStatusCode.RequestTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<RestResult<T>> DeleteAsync<T>(Uri uri, CancellationToken cancellationToken)
|
||||
{
|
||||
_debug.Debug("DELETE " + uri);
|
||||
try
|
||||
{
|
||||
var response = await _client.DeleteAsync(uri, cancellationToken);
|
||||
return await ReadResult<T>(response, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_debug.Debug("ERROR " + ex.Message);
|
||||
return new RestResult<T>(default, ex.Message, HttpStatusCode.RequestTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<RestResult<T>> ReadResult<T>(HttpResponseMessage response, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
//_debug.Debug("CONTENT:" + content);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
_debug.Debug($"SUCCESSFUL GET CONTENT {typeof(T)}");
|
||||
if (typeof(T) == typeof(RawResult))
|
||||
return (new RestResult<RawResult>(new RawResult(content), null, response.StatusCode) as RestResult<T>)!;
|
||||
|
||||
return new RestResult<T>(JsonSerializer.Deserialize<T>(content, _serializerOptions), null,
|
||||
response.StatusCode);
|
||||
}
|
||||
|
||||
_debug.Error("ERROR " + response.StatusCode + " " + content);
|
||||
return new RestResult<T>(default, "response code:" + response.StatusCode, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public class RestResult<T>
|
||||
{
|
||||
public string? Message;
|
||||
public HttpStatusCode StatusCode;
|
||||
public T? Value;
|
||||
|
||||
public RestResult(T? value, string? message, HttpStatusCode statusCode)
|
||||
{
|
||||
Value = value;
|
||||
Message = message;
|
||||
StatusCode = statusCode;
|
||||
}
|
||||
|
||||
public static implicit operator T?(RestResult<T> result)
|
||||
{
|
||||
return result.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public class RawResult
|
||||
{
|
||||
public string Result;
|
||||
|
||||
public RawResult(string result)
|
||||
{
|
||||
Result = result;
|
||||
}
|
||||
|
||||
public static implicit operator string(RawResult result)
|
||||
{
|
||||
return result.Result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user