- fix: auth logic part 2
This commit is contained in:
99
Nebula.Launcher/Configurations/ArrayUnitConfigControl.cs
Normal file
99
Nebula.Launcher/Configurations/ArrayUnitConfigControl.cs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Layout;
|
||||||
|
|
||||||
|
namespace Nebula.Launcher.ViewModels.Pages;
|
||||||
|
|
||||||
|
public sealed class ArrayUnitConfigControl : Border, IConfigControl
|
||||||
|
{
|
||||||
|
private readonly List<IConfigControl> _itemControls = [];
|
||||||
|
private readonly StackPanel _itemsPanel = new StackPanel() { Orientation = Orientation.Vertical };
|
||||||
|
private readonly Button _addButton = new Button() { Content = new Label()
|
||||||
|
{
|
||||||
|
Content = "Add Item"
|
||||||
|
}, Classes = { "ConfigBorder" }};
|
||||||
|
private readonly int _oldCount;
|
||||||
|
private readonly Type _elementType;
|
||||||
|
private readonly StackPanel _panel = new();
|
||||||
|
|
||||||
|
public string ConfigName { get; }
|
||||||
|
public bool Dirty => _itemControls.Any(dirty => dirty.Dirty) || _itemControls.Count != _oldCount;
|
||||||
|
|
||||||
|
public ArrayUnitConfigControl(string name, object value)
|
||||||
|
{
|
||||||
|
Classes.Add("ConfigBorder");
|
||||||
|
_elementType = value.GetType().GetElementType()!;
|
||||||
|
|
||||||
|
ConfigName = name;
|
||||||
|
_panel.Orientation = Orientation.Vertical;
|
||||||
|
_panel.Spacing = 4f;
|
||||||
|
_itemsPanel.Spacing = 4f;
|
||||||
|
|
||||||
|
_panel.Children.Add(new Label { Content = name });
|
||||||
|
_panel.Children.Add(_itemsPanel);
|
||||||
|
_panel.Children.Add(_addButton);
|
||||||
|
|
||||||
|
_addButton.Click += (_, _) => AddItem(ConfigControlHelper.CreateDefaultValue(_elementType)!);
|
||||||
|
Child = _panel;
|
||||||
|
SetValue(value);
|
||||||
|
_oldCount = _itemControls.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddItem(object value)
|
||||||
|
{
|
||||||
|
var itemPanel = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 2 };
|
||||||
|
var control = ConfigControlHelper.GetConfigControl(_itemControls.Count.ToString(), value);
|
||||||
|
var removeButton = new Button { Content = new Label(){ Content = "Remove" }, Classes = { "ConfigBorder" }};
|
||||||
|
|
||||||
|
removeButton.Click += (_, _) =>
|
||||||
|
{
|
||||||
|
_itemControls.Remove(control);
|
||||||
|
_itemsPanel.Children.Remove(itemPanel);
|
||||||
|
};
|
||||||
|
|
||||||
|
((Control)control).Margin = new Thickness(5);
|
||||||
|
itemPanel.Children.Add((Control)control);
|
||||||
|
itemPanel.Children.Add(removeButton);
|
||||||
|
|
||||||
|
_itemsPanel.Children.Add(itemPanel);
|
||||||
|
_itemControls.Add(control);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(object value)
|
||||||
|
{
|
||||||
|
_itemControls.Clear();
|
||||||
|
_itemsPanel.Children.Clear();
|
||||||
|
|
||||||
|
if (value is IEnumerable list)
|
||||||
|
{
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
AddItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetValue()
|
||||||
|
{
|
||||||
|
return ConvertArray(_itemControls.Select(c => c.GetValue()).ToArray(), _elementType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Array ConvertArray(Array sourceArray, Type targetType)
|
||||||
|
{
|
||||||
|
int length = sourceArray.Length;
|
||||||
|
var newArray = Array.CreateInstance(targetType, length);
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
var value = sourceArray.GetValue(i);
|
||||||
|
var converted = Convert.ChangeType(value, targetType);
|
||||||
|
newArray.SetValue(converted, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Nebula.Shared.Configurations;
|
||||||
|
|
||||||
namespace Nebula.Shared.Configurations;
|
namespace Nebula.Launcher.Configurations;
|
||||||
|
|
||||||
public abstract class ComplexConVarBinder<T> : INotifyPropertyChanged, INotifyPropertyChanging
|
public abstract class ComplexConVarBinder<T> : INotifyPropertyChanged, INotifyPropertyChanging
|
||||||
{
|
{
|
||||||
@@ -23,6 +26,17 @@ public abstract class ComplexConVarBinder<T> : INotifyPropertyChanged, INotifyPr
|
|||||||
_ = SetValueAsync(value);
|
_ = SetValueAsync(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool HasValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
return _baseConVar.HasValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected ComplexConVarBinder(ConVarObserver<T> baseConVar)
|
protected ComplexConVarBinder(ConVarObserver<T> baseConVar)
|
||||||
{
|
{
|
||||||
@@ -55,11 +69,13 @@ public abstract class ComplexConVarBinder<T> : INotifyPropertyChanged, INotifyPr
|
|||||||
|
|
||||||
private void BaseConVarOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
private void BaseConVarOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasValue)));
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BaseConVarOnPropertyChanging(object? sender, PropertyChangingEventArgs e)
|
private void BaseConVarOnPropertyChanging(object? sender, PropertyChangingEventArgs e)
|
||||||
{
|
{
|
||||||
|
PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(nameof(HasValue)));
|
||||||
PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(nameof(Value)));
|
PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(nameof(Value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
68
Nebula.Launcher/Configurations/ComplexUnitConfigControl.cs
Normal file
68
Nebula.Launcher/Configurations/ComplexUnitConfigControl.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Layout;
|
||||||
|
|
||||||
|
namespace Nebula.Launcher.ViewModels.Pages;
|
||||||
|
|
||||||
|
public sealed class ComplexUnitConfigControl : Border, IConfigControl
|
||||||
|
{
|
||||||
|
private readonly List<(PropertyInfo, IConfigControl)> _units = [];
|
||||||
|
|
||||||
|
private Type _objectType = typeof(object);
|
||||||
|
|
||||||
|
private readonly StackPanel _panel = new();
|
||||||
|
|
||||||
|
public string ConfigName { get; }
|
||||||
|
public bool Dirty => _units.Any(dirty => dirty.Item2.Dirty);
|
||||||
|
|
||||||
|
public ComplexUnitConfigControl(string name, object obj)
|
||||||
|
{
|
||||||
|
Classes.Add("ConfigBorder");
|
||||||
|
_panel.Orientation = Orientation.Vertical;
|
||||||
|
_panel.Spacing = 4f;
|
||||||
|
ConfigName = name;
|
||||||
|
Child = _panel;
|
||||||
|
SetValue(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(object value)
|
||||||
|
{
|
||||||
|
_units.Clear();
|
||||||
|
_panel.Children.Clear();
|
||||||
|
_objectType = value.GetType();
|
||||||
|
|
||||||
|
_panel.Children.Add(new Label()
|
||||||
|
{
|
||||||
|
Content = ConfigName
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var propInfo in _objectType.GetProperties())
|
||||||
|
{
|
||||||
|
if(propInfo.PropertyType.IsInterface)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var propValue = propInfo.GetValue(value);
|
||||||
|
|
||||||
|
var control = ConfigControlHelper.GetConfigControl(propInfo.Name, propValue!);
|
||||||
|
|
||||||
|
((Control)control).Margin = new Thickness(5);
|
||||||
|
_panel.Children.Add((Control)control);
|
||||||
|
_units.Add((propInfo,control));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetValue()
|
||||||
|
{
|
||||||
|
var obj = ConfigControlHelper.CreateDefaultValue(_objectType);
|
||||||
|
foreach (var (fieldInfo, configControl) in _units)
|
||||||
|
{
|
||||||
|
fieldInfo.SetValue(obj, configControl.GetValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj!;
|
||||||
|
}
|
||||||
|
}
|
||||||
39
Nebula.Launcher/Configurations/ConfigControlHelper.cs
Normal file
39
Nebula.Launcher/Configurations/ConfigControlHelper.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Nebula.Launcher.ViewModels.Pages;
|
||||||
|
|
||||||
|
public static class ConfigControlHelper{
|
||||||
|
public static IConfigControl GetConfigControl(string name,object value)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case string stringValue:
|
||||||
|
return new StringUnitConfigControl(name, stringValue);
|
||||||
|
case int intValue:
|
||||||
|
return new IntUnitConfigControl(name, intValue);
|
||||||
|
case float floatValue:
|
||||||
|
return new FloatUnitConfigControl(name, floatValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
var valueType = value.GetType();
|
||||||
|
|
||||||
|
if (valueType.IsArray)
|
||||||
|
return new ArrayUnitConfigControl(name, value);
|
||||||
|
|
||||||
|
return new ComplexUnitConfigControl(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object? CreateDefaultValue(Type type)
|
||||||
|
{
|
||||||
|
if(type.IsValueType)
|
||||||
|
return Activator.CreateInstance(type);
|
||||||
|
|
||||||
|
var ctor = type.GetConstructors().First();
|
||||||
|
var parameters = ctor.GetParameters()
|
||||||
|
.Select(p => CreateDefaultValue(p.ParameterType))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return ctor.Invoke(parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Nebula.Launcher/Configurations/FloatUnitConfigControl.cs
Normal file
19
Nebula.Launcher/Configurations/FloatUnitConfigControl.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Nebula.Launcher.ViewModels.Pages;
|
||||||
|
|
||||||
|
public sealed class FloatUnitConfigControl(string name, float value) : UnitConfigControl<float>(name, value)
|
||||||
|
{
|
||||||
|
|
||||||
|
public CultureInfo CultureInfo = CultureInfo.InvariantCulture;
|
||||||
|
|
||||||
|
public override void SetConfValue(float value)
|
||||||
|
{
|
||||||
|
ConfigValue = value.ToString(CultureInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetConfValue()
|
||||||
|
{
|
||||||
|
return float.Parse(ConfigValue, CultureInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Nebula.Launcher/Configurations/IConfigControl.cs
Normal file
9
Nebula.Launcher/Configurations/IConfigControl.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Nebula.Launcher.ViewModels.Pages;
|
||||||
|
|
||||||
|
public interface IConfigControl
|
||||||
|
{
|
||||||
|
public string ConfigName { get; }
|
||||||
|
public bool Dirty {get;}
|
||||||
|
public abstract void SetValue(object value);
|
||||||
|
public abstract object GetValue();
|
||||||
|
}
|
||||||
14
Nebula.Launcher/Configurations/IntUnitConfigControl.cs
Normal file
14
Nebula.Launcher/Configurations/IntUnitConfigControl.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Nebula.Launcher.ViewModels.Pages;
|
||||||
|
|
||||||
|
public sealed class IntUnitConfigControl(string name, int value) : UnitConfigControl<int>(name, value)
|
||||||
|
{
|
||||||
|
public override void SetConfValue(int value)
|
||||||
|
{
|
||||||
|
ConfigValue = value.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetConfValue()
|
||||||
|
{
|
||||||
|
return int.Parse(ConfigValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
14
Nebula.Launcher/Configurations/StringUnitConfigControl.cs
Normal file
14
Nebula.Launcher/Configurations/StringUnitConfigControl.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Nebula.Launcher.ViewModels.Pages;
|
||||||
|
|
||||||
|
public sealed class StringUnitConfigControl(string name, string value) : UnitConfigControl<string>(name, value)
|
||||||
|
{
|
||||||
|
public override void SetConfValue(string value)
|
||||||
|
{
|
||||||
|
ConfigValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetConfValue()
|
||||||
|
{
|
||||||
|
return ConfigValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
Nebula.Launcher/Configurations/UnitConfigControl.cs
Normal file
53
Nebula.Launcher/Configurations/UnitConfigControl.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Layout;
|
||||||
|
|
||||||
|
namespace Nebula.Launcher.ViewModels.Pages;
|
||||||
|
|
||||||
|
public abstract class UnitConfigControl<T> : Border, IConfigControl where T : notnull
|
||||||
|
{
|
||||||
|
private readonly Label _nameLabel = new();
|
||||||
|
private readonly TextBox _valueLabel = new();
|
||||||
|
private string _originalValue;
|
||||||
|
|
||||||
|
private StackPanel _panel = new();
|
||||||
|
|
||||||
|
public string ConfigName { get; }
|
||||||
|
|
||||||
|
public bool Dirty => _originalValue != ConfigValue;
|
||||||
|
|
||||||
|
protected string ConfigValue
|
||||||
|
{
|
||||||
|
get => _valueLabel.Text ?? string.Empty;
|
||||||
|
set => _valueLabel.Text = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnitConfigControl(string name, T value)
|
||||||
|
{
|
||||||
|
Classes.Add("ConfigBorder");
|
||||||
|
ConfigName = name;
|
||||||
|
_panel.Orientation = Orientation.Horizontal;
|
||||||
|
_panel.Children.Add(_nameLabel);
|
||||||
|
_panel.Children.Add(_valueLabel);
|
||||||
|
|
||||||
|
_nameLabel.Content = name;
|
||||||
|
_nameLabel.VerticalAlignment = VerticalAlignment.Center;
|
||||||
|
Child = _panel;
|
||||||
|
|
||||||
|
SetConfValue(value);
|
||||||
|
_originalValue = ConfigValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void SetConfValue(T value);
|
||||||
|
|
||||||
|
public abstract T GetConfValue();
|
||||||
|
|
||||||
|
public void SetValue(object value)
|
||||||
|
{
|
||||||
|
SetConfValue((T)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetValue()
|
||||||
|
{
|
||||||
|
return GetConfValue()!;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -68,12 +68,16 @@ public partial class LocalisationService
|
|||||||
public class LocaledText : MarkupExtension
|
public class LocaledText : MarkupExtension
|
||||||
{
|
{
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
|
public Dictionary<string, object>? Options { get; set; }
|
||||||
|
|
||||||
public LocaledText(string key) => Key = key;
|
public LocaledText(string key) => Key = key;
|
||||||
|
|
||||||
|
public LocaledText()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
// Fetch the localized string using the key
|
return LocalisationService.GetString(Key, Options);
|
||||||
return LocalisationService.GetString(Key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,16 +40,8 @@ public partial class MainViewModel : ViewModelBase
|
|||||||
[ObservableProperty] private bool _isPopupClosable = true;
|
[ObservableProperty] private bool _isPopupClosable = true;
|
||||||
[ObservableProperty] private bool _popup;
|
[ObservableProperty] private bool _popup;
|
||||||
[ObservableProperty] private ListItemTemplate? _selectedListItem;
|
[ObservableProperty] private ListItemTemplate? _selectedListItem;
|
||||||
|
[ObservableProperty] private string? _loginText = LocalisationService.GetString("auth-current-login-no-name");
|
||||||
public bool IsLoggedIn => AccountInfoViewModel.Credentials.Value is not null;
|
|
||||||
|
|
||||||
public string LoginText => LocalisationService.GetString("auth-current-login-name",
|
|
||||||
new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{ "login", AccountInfoViewModel.Credentials.Value?.Login ?? "" },
|
|
||||||
{ "auth_server", AccountInfoViewModel.CurrentAuthServerName}
|
|
||||||
});
|
|
||||||
|
|
||||||
[GenerateProperty] private LocalisationService LocalisationService { get; } // Не убирать! Без этой хуйни вся локализация идет в пизду!
|
[GenerateProperty] private LocalisationService LocalisationService { get; } // Не убирать! Без этой хуйни вся локализация идет в пизду!
|
||||||
[GenerateProperty] private AccountInfoViewModel AccountInfoViewModel { get; }
|
[GenerateProperty] private AccountInfoViewModel AccountInfoViewModel { get; }
|
||||||
[GenerateProperty] private DebugService DebugService { get; } = default!;
|
[GenerateProperty] private DebugService DebugService { get; } = default!;
|
||||||
@@ -74,15 +66,29 @@ public partial class MainViewModel : ViewModelBase
|
|||||||
|
|
||||||
protected override void Initialise()
|
protected override void Initialise()
|
||||||
{
|
{
|
||||||
AccountInfoViewModel.PropertyChanged += (sender, args) =>
|
AccountInfoViewModel.Credentials.PropertyChanged += (_, args) =>
|
||||||
{
|
{
|
||||||
if (args.PropertyName != nameof(AccountInfoViewModel.Credentials))
|
if (args.PropertyName is not nameof(AccountInfoViewModel.Credentials.Value)) return;
|
||||||
return;
|
|
||||||
|
|
||||||
OnPropertyChanged(nameof(LoginText));
|
if(AccountInfoViewModel.Credentials.HasValue)
|
||||||
OnPropertyChanged(nameof(IsLoggedIn));
|
{
|
||||||
|
LoginText =
|
||||||
|
LocalisationService.GetString("auth-current-login-name",
|
||||||
|
new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "login", AccountInfoViewModel.Credentials.Value?.Login ?? "" },
|
||||||
|
{
|
||||||
|
"auth_server",
|
||||||
|
AccountInfoViewModel.GetServerAuthName(AccountInfoViewModel.Credentials.Value) ?? ""
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LoginText = LocalisationService.GetString("auth-current-login-no-name");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_logger = DebugService.GetLogger(this);
|
_logger = DebugService.GetLogger(this);
|
||||||
|
|
||||||
using var stream = typeof(MainViewModel).Assembly
|
using var stream = typeof(MainViewModel).Assembly
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using Nebula.Launcher.Configurations;
|
||||||
using Nebula.Launcher.Models.Auth;
|
using Nebula.Launcher.Models.Auth;
|
||||||
using Nebula.Launcher.Services;
|
using Nebula.Launcher.Services;
|
||||||
using Nebula.Launcher.ViewModels.Popup;
|
using Nebula.Launcher.ViewModels.Popup;
|
||||||
@@ -41,9 +42,8 @@ public partial class AccountInfoViewModel : ViewModelBase
|
|||||||
|
|
||||||
public ObservableCollection<ProfileAuthCredentials> Accounts { get; } = new();
|
public ObservableCollection<ProfileAuthCredentials> Accounts { get; } = new();
|
||||||
public ObservableCollection<AuthServerCredentials> AuthUrls { get; } = new();
|
public ObservableCollection<AuthServerCredentials> AuthUrls { get; } = new();
|
||||||
public string CurrentAuthServerName => GetServerAuthName(Credentials.Value);
|
|
||||||
|
|
||||||
public ComplexConVarBinder<AuthTokenCredentials?> Credentials;
|
public ComplexConVarBinder<AuthTokenCredentials?> Credentials { get; private set; }
|
||||||
|
|
||||||
private ILogger _logger;
|
private ILogger _logger;
|
||||||
|
|
||||||
@@ -303,8 +303,8 @@ public partial class AccountInfoViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
var unexpectedError = new Exception(LocalisationService.GetString("auth-error"), e);
|
var unexpectedError = new Exception(LocalisationService.GetString("auth-error"), e);
|
||||||
_logger.Error(unexpectedError);
|
_logger.Error(unexpectedError);
|
||||||
PopupMessageService.Popup(unexpectedError);
|
//PopupMessageService.Popup(unexpectedError);
|
||||||
return null;
|
return authTokenCredentials;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,7 +364,6 @@ public partial class AccountInfoViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
accountInfoViewModel.IsLogged = false;
|
accountInfoViewModel.IsLogged = false;
|
||||||
accountInfoViewModel._logger.Log("clearing credentials");
|
accountInfoViewModel._logger.Log("clearing credentials");
|
||||||
accountInfoViewModel.OnPropertyChanged(nameof(CurrentAuthServerName));
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,8 +407,7 @@ public partial class AccountInfoViewModel : ViewModelBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
accountInfoViewModel.IsLogged = true;
|
accountInfoViewModel.IsLogged = true;
|
||||||
accountInfoViewModel.OnPropertyChanged(nameof(CurrentAuthServerName));
|
|
||||||
|
|
||||||
return currProfile;
|
return currProfile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Layout;
|
|
||||||
using Nebula.Launcher.Services;
|
using Nebula.Launcher.Services;
|
||||||
using Nebula.Launcher.ViewModels.Popup;
|
using Nebula.Launcher.ViewModels.Popup;
|
||||||
using Nebula.Launcher.Views.Pages;
|
using Nebula.Launcher.Views.Pages;
|
||||||
@@ -119,288 +112,4 @@ public partial class ConfigurationViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
InitConfiguration();
|
InitConfiguration();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static class ConfigControlHelper{
|
|
||||||
public static IConfigControl GetConfigControl(string name,object value)
|
|
||||||
{
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case string stringValue:
|
|
||||||
return new StringUnitConfigControl(name, stringValue);
|
|
||||||
case int intValue:
|
|
||||||
return new IntUnitConfigControl(name, intValue);
|
|
||||||
case float floatValue:
|
|
||||||
return new FloatUnitConfigControl(name, floatValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
var valueType = value.GetType();
|
|
||||||
|
|
||||||
if (valueType.IsArray)
|
|
||||||
return new ArrayUnitConfigControl(name, value);
|
|
||||||
|
|
||||||
return new ComplexUnitConfigControl(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object? CreateDefaultValue(Type type)
|
|
||||||
{
|
|
||||||
if(type.IsValueType)
|
|
||||||
return Activator.CreateInstance(type);
|
|
||||||
|
|
||||||
var ctor = type.GetConstructors().First();
|
|
||||||
var parameters = ctor.GetParameters()
|
|
||||||
.Select(p => CreateDefaultValue(p.ParameterType))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
return ctor.Invoke(parameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ComplexUnitConfigControl : Border, IConfigControl
|
|
||||||
{
|
|
||||||
private readonly List<(PropertyInfo, IConfigControl)> _units = [];
|
|
||||||
|
|
||||||
private Type _objectType = typeof(object);
|
|
||||||
|
|
||||||
private readonly StackPanel _panel = new();
|
|
||||||
|
|
||||||
public string ConfigName { get; }
|
|
||||||
public bool Dirty => _units.Any(dirty => dirty.Item2.Dirty);
|
|
||||||
|
|
||||||
public ComplexUnitConfigControl(string name, object obj)
|
|
||||||
{
|
|
||||||
Classes.Add("ConfigBorder");
|
|
||||||
_panel.Orientation = Orientation.Vertical;
|
|
||||||
_panel.Spacing = 4f;
|
|
||||||
ConfigName = name;
|
|
||||||
Child = _panel;
|
|
||||||
SetValue(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetValue(object value)
|
|
||||||
{
|
|
||||||
_units.Clear();
|
|
||||||
_panel.Children.Clear();
|
|
||||||
_objectType = value.GetType();
|
|
||||||
|
|
||||||
_panel.Children.Add(new Label()
|
|
||||||
{
|
|
||||||
Content = ConfigName
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var propInfo in _objectType.GetProperties())
|
|
||||||
{
|
|
||||||
if(propInfo.PropertyType.IsInterface)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var propValue = propInfo.GetValue(value);
|
|
||||||
|
|
||||||
var control = ConfigControlHelper.GetConfigControl(propInfo.Name, propValue!);
|
|
||||||
|
|
||||||
((Control)control).Margin = new Thickness(5);
|
|
||||||
_panel.Children.Add((Control)control);
|
|
||||||
_units.Add((propInfo,control));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object GetValue()
|
|
||||||
{
|
|
||||||
var obj = ConfigControlHelper.CreateDefaultValue(_objectType);
|
|
||||||
foreach (var (fieldInfo, configControl) in _units)
|
|
||||||
{
|
|
||||||
fieldInfo.SetValue(obj, configControl.GetValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ArrayUnitConfigControl : Border, IConfigControl
|
|
||||||
{
|
|
||||||
private readonly List<IConfigControl> _itemControls = [];
|
|
||||||
private readonly StackPanel _itemsPanel = new StackPanel() { Orientation = Orientation.Vertical };
|
|
||||||
private readonly Button _addButton = new Button() { Content = new Label()
|
|
||||||
{
|
|
||||||
Content = "Add Item"
|
|
||||||
}, Classes = { "ConfigBorder" }};
|
|
||||||
private readonly int _oldCount;
|
|
||||||
private readonly Type _elementType;
|
|
||||||
private readonly StackPanel _panel = new();
|
|
||||||
|
|
||||||
public string ConfigName { get; }
|
|
||||||
public bool Dirty => _itemControls.Any(dirty => dirty.Dirty) || _itemControls.Count != _oldCount;
|
|
||||||
|
|
||||||
public ArrayUnitConfigControl(string name, object value)
|
|
||||||
{
|
|
||||||
Classes.Add("ConfigBorder");
|
|
||||||
_elementType = value.GetType().GetElementType()!;
|
|
||||||
|
|
||||||
ConfigName = name;
|
|
||||||
_panel.Orientation = Orientation.Vertical;
|
|
||||||
_panel.Spacing = 4f;
|
|
||||||
_itemsPanel.Spacing = 4f;
|
|
||||||
|
|
||||||
_panel.Children.Add(new Label { Content = name });
|
|
||||||
_panel.Children.Add(_itemsPanel);
|
|
||||||
_panel.Children.Add(_addButton);
|
|
||||||
|
|
||||||
_addButton.Click += (_, _) => AddItem(ConfigControlHelper.CreateDefaultValue(_elementType)!);
|
|
||||||
Child = _panel;
|
|
||||||
SetValue(value);
|
|
||||||
_oldCount = _itemControls.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddItem(object value)
|
|
||||||
{
|
|
||||||
var itemPanel = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 2 };
|
|
||||||
var control = ConfigControlHelper.GetConfigControl(_itemControls.Count.ToString(), value);
|
|
||||||
var removeButton = new Button { Content = new Label(){ Content = "Remove" }, Classes = { "ConfigBorder" }};
|
|
||||||
|
|
||||||
removeButton.Click += (_, _) =>
|
|
||||||
{
|
|
||||||
_itemControls.Remove(control);
|
|
||||||
_itemsPanel.Children.Remove(itemPanel);
|
|
||||||
};
|
|
||||||
|
|
||||||
((Control)control).Margin = new Thickness(5);
|
|
||||||
itemPanel.Children.Add((Control)control);
|
|
||||||
itemPanel.Children.Add(removeButton);
|
|
||||||
|
|
||||||
_itemsPanel.Children.Add(itemPanel);
|
|
||||||
_itemControls.Add(control);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetValue(object value)
|
|
||||||
{
|
|
||||||
_itemControls.Clear();
|
|
||||||
_itemsPanel.Children.Clear();
|
|
||||||
|
|
||||||
if (value is IEnumerable list)
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
AddItem(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object GetValue()
|
|
||||||
{
|
|
||||||
return ConvertArray(_itemControls.Select(c => c.GetValue()).ToArray(), _elementType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Array ConvertArray(Array sourceArray, Type targetType)
|
|
||||||
{
|
|
||||||
int length = sourceArray.Length;
|
|
||||||
var newArray = Array.CreateInstance(targetType, length);
|
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
var value = sourceArray.GetValue(i);
|
|
||||||
var converted = Convert.ChangeType(value, targetType);
|
|
||||||
newArray.SetValue(converted, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class UnitConfigControl<T> : Border, IConfigControl where T : notnull
|
|
||||||
{
|
|
||||||
private readonly Label _nameLabel = new();
|
|
||||||
private readonly TextBox _valueLabel = new();
|
|
||||||
private string _originalValue;
|
|
||||||
|
|
||||||
private StackPanel _panel = new();
|
|
||||||
|
|
||||||
public string ConfigName { get; }
|
|
||||||
|
|
||||||
public bool Dirty => _originalValue != ConfigValue;
|
|
||||||
|
|
||||||
protected string ConfigValue
|
|
||||||
{
|
|
||||||
get => _valueLabel.Text ?? string.Empty;
|
|
||||||
set => _valueLabel.Text = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnitConfigControl(string name, T value)
|
|
||||||
{
|
|
||||||
Classes.Add("ConfigBorder");
|
|
||||||
ConfigName = name;
|
|
||||||
_panel.Orientation = Orientation.Horizontal;
|
|
||||||
_panel.Children.Add(_nameLabel);
|
|
||||||
_panel.Children.Add(_valueLabel);
|
|
||||||
|
|
||||||
_nameLabel.Content = name;
|
|
||||||
_nameLabel.VerticalAlignment = VerticalAlignment.Center;
|
|
||||||
Child = _panel;
|
|
||||||
|
|
||||||
SetConfValue(value);
|
|
||||||
_originalValue = ConfigValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void SetConfValue(T value);
|
|
||||||
|
|
||||||
public abstract T GetConfValue();
|
|
||||||
|
|
||||||
public void SetValue(object value)
|
|
||||||
{
|
|
||||||
SetConfValue((T)value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object GetValue()
|
|
||||||
{
|
|
||||||
return GetConfValue()!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class StringUnitConfigControl(string name, string value) : UnitConfigControl<string>(name, value)
|
|
||||||
{
|
|
||||||
public override void SetConfValue(string value)
|
|
||||||
{
|
|
||||||
ConfigValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string GetConfValue()
|
|
||||||
{
|
|
||||||
return ConfigValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class IntUnitConfigControl(string name, int value) : UnitConfigControl<int>(name, value)
|
|
||||||
{
|
|
||||||
public override void SetConfValue(int value)
|
|
||||||
{
|
|
||||||
ConfigValue = value.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetConfValue()
|
|
||||||
{
|
|
||||||
return int.Parse(ConfigValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class FloatUnitConfigControl(string name, float value) : UnitConfigControl<float>(name, value)
|
|
||||||
{
|
|
||||||
|
|
||||||
public CultureInfo CultureInfo = CultureInfo.InvariantCulture;
|
|
||||||
|
|
||||||
public override void SetConfValue(float value)
|
|
||||||
{
|
|
||||||
ConfigValue = value.ToString(CultureInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float GetConfValue()
|
|
||||||
{
|
|
||||||
return float.Parse(ConfigValue, CultureInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public interface IConfigControl
|
|
||||||
{
|
|
||||||
public string ConfigName { get; }
|
|
||||||
public bool Dirty {get;}
|
|
||||||
public abstract void SetValue(object value);
|
|
||||||
public abstract object GetValue();
|
|
||||||
}
|
}
|
||||||
@@ -133,8 +133,9 @@
|
|||||||
Path="/Assets/svg/user.svg"
|
Path="/Assets/svg/user.svg"
|
||||||
Width="10" />
|
Width="10" />
|
||||||
<Panel>
|
<Panel>
|
||||||
<TextBlock Foreground="#777777" IsVisible="{Binding IsLoggedIn}" Text="{Binding LoginText}"/>
|
<TextBlock
|
||||||
<TextBlock Foreground="#777777" IsVisible="{Binding !IsLoggedIn}" Text="{services:LocaledText auth-current-login-no-name}"/>
|
Foreground="#777777"
|
||||||
|
Text="{Binding LoginText}"/>
|
||||||
</Panel>
|
</Panel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -191,11 +191,11 @@
|
|||||||
<StackPanel>
|
<StackPanel>
|
||||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="5">
|
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="5">
|
||||||
<customControls:LocalizedLabel LocalId="account-auth-hello"/>
|
<customControls:LocalizedLabel LocalId="account-auth-hello"/>
|
||||||
<TextBlock Text="{Binding CurrentLogin}" />
|
<TextBlock Text="{Binding Credentials.Value.Login}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="5">
|
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="5">
|
||||||
<customControls:LocalizedLabel LocalId="account-auth-current-server"/>
|
<customControls:LocalizedLabel LocalId="account-auth-current-server"/>
|
||||||
<TextBlock Text="{Binding CurrentAuthServerName}" />
|
<TextBlock Text="{Binding Credentials.Value.AuthServer}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Label>
|
</Label>
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ public sealed class ConVarObserver<T> : IDisposable, INotifyPropertyChanged, INo
|
|||||||
private T? _value;
|
private T? _value;
|
||||||
private ConfigurationService.OnConfigurationChangedDelegate<T> _delegate;
|
private ConfigurationService.OnConfigurationChangedDelegate<T> _delegate;
|
||||||
|
|
||||||
|
public bool HasValue => Value != null;
|
||||||
|
|
||||||
public T? Value
|
public T? Value
|
||||||
{
|
{
|
||||||
get => _value;
|
get => _value;
|
||||||
@@ -31,6 +33,7 @@ public sealed class ConVarObserver<T> : IDisposable, INotifyPropertyChanged, INo
|
|||||||
private void OnValueChanged(T? value)
|
private void OnValueChanged(T? value)
|
||||||
{
|
{
|
||||||
OnPropertyChanging(nameof(Value));
|
OnPropertyChanging(nameof(Value));
|
||||||
|
OnPropertyChanging(nameof(HasValue));
|
||||||
|
|
||||||
if(value is null && _value is null)
|
if(value is null && _value is null)
|
||||||
return;
|
return;
|
||||||
@@ -39,17 +42,13 @@ public sealed class ConVarObserver<T> : IDisposable, INotifyPropertyChanged, INo
|
|||||||
|
|
||||||
_value = value;
|
_value = value;
|
||||||
OnPropertyChanged(nameof(Value));
|
OnPropertyChanged(nameof(Value));
|
||||||
|
OnPropertyChanged(nameof(HasValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_convar.OnValueChanged -= OnValueChanged;
|
_convar.OnValueChanged -= OnValueChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasValue()
|
|
||||||
{
|
|
||||||
return Value != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator T? (ConVarObserver<T> convar) => convar.Value;
|
public static implicit operator T? (ConVarObserver<T> convar) => convar.Value;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Nebula.Shared.FileApis;
|
|
||||||
using Nebula.Shared.Services.Logging;
|
using Nebula.Shared.Services.Logging;
|
||||||
using Robust.LoaderApi;
|
|
||||||
|
|
||||||
namespace Nebula.Shared.Services;
|
namespace Nebula.Shared.Services;
|
||||||
|
|
||||||
@@ -9,16 +8,23 @@ namespace Nebula.Shared.Services;
|
|||||||
public class DebugService : IDisposable
|
public class DebugService : IDisposable
|
||||||
{
|
{
|
||||||
public static bool DoFileLog;
|
public static bool DoFileLog;
|
||||||
private ServiceLogger Root {get; set;}
|
|
||||||
|
|
||||||
private readonly string _path =
|
private readonly string _path =
|
||||||
Path.Combine(FileService.RootPath, "log", Assembly.GetEntryAssembly()?.GetName().Name ?? "App");
|
Path.Combine(FileService.RootPath, "log", Assembly.GetEntryAssembly()?.GetName().Name ?? "App");
|
||||||
|
|
||||||
public DebugService()
|
public DebugService()
|
||||||
{
|
{
|
||||||
ClearLog();
|
ClearLog();
|
||||||
Root = new ServiceLogger("Root",_path);
|
Root = new ServiceLogger("Root", _path);
|
||||||
Root.GetLogger("DebugService").Log("Initializing debug service " + (DoFileLog ? "with file logging" : "without file logging"));
|
Root.GetLogger("DebugService")
|
||||||
|
.Log("Initializing debug service " + (DoFileLog ? "with file logging" : "without file logging"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServiceLogger Root { get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Root.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ILogger GetLogger(string loggerName)
|
public ILogger GetLogger(string loggerName)
|
||||||
@@ -31,25 +37,14 @@ public class DebugService : IDisposable
|
|||||||
return Root.GetLogger(objectToLog.GetType().Name);
|
return Root.GetLogger(objectToLog.GetType().Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Root.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearLog()
|
private void ClearLog()
|
||||||
{
|
{
|
||||||
if(!Directory.Exists(_path))
|
if (!Directory.Exists(_path))
|
||||||
return;
|
return;
|
||||||
var di = new DirectoryInfo(_path);
|
var di = new DirectoryInfo(_path);
|
||||||
|
|
||||||
foreach (var file in di.GetFiles())
|
foreach (var file in di.GetFiles()) file.Delete();
|
||||||
{
|
foreach (var dir in di.GetDirectories()) dir.Delete(true);
|
||||||
file.Delete();
|
|
||||||
}
|
|
||||||
foreach (var dir in di.GetDirectories())
|
|
||||||
{
|
|
||||||
dir.Delete(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,101 +58,101 @@ public enum LoggerCategory
|
|||||||
internal class ServiceLogger : ILogger
|
internal class ServiceLogger : ILogger
|
||||||
{
|
{
|
||||||
private readonly string _directory;
|
private readonly string _directory;
|
||||||
public ServiceLogger? Root { get; private set; }
|
private readonly string _path;
|
||||||
|
|
||||||
public ServiceLogger(string category, string directory)
|
public ServiceLogger(string category, string directory)
|
||||||
{
|
{
|
||||||
_directory = directory;
|
_directory = directory;
|
||||||
Category = category;
|
Category = category;
|
||||||
|
|
||||||
if (!DebugService.DoFileLog) return;
|
if (!DebugService.DoFileLog) return;
|
||||||
|
|
||||||
if(!Directory.Exists(directory)) Directory.CreateDirectory(directory);
|
if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);
|
||||||
|
|
||||||
_path = Path.Combine(directory, $"{Category}.log");
|
_path = Path.Combine(directory, $"{Category}.log");
|
||||||
|
|
||||||
File.Create(_path).Dispose();
|
File.Create(_path).Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Category { get; init; }
|
public ServiceLogger? Root { get; private set; }
|
||||||
|
|
||||||
private Dictionary<string, ServiceLogger> Childs { get; init; } = new();
|
public string Category { get; init; }
|
||||||
|
private ConcurrentDictionary<string, ServiceLogger> Childs { get; } = new();
|
||||||
private FileStream? _fileStream;
|
|
||||||
private StreamWriter? _streamWriter;
|
|
||||||
private readonly string _path;
|
|
||||||
|
|
||||||
public ServiceLogger GetLogger(string category)
|
|
||||||
{
|
|
||||||
if (Childs.TryGetValue(category, out var logger))
|
|
||||||
return logger;
|
|
||||||
|
|
||||||
logger = new ServiceLogger(category, _directory);
|
|
||||||
logger.Root = this;
|
|
||||||
Childs.Add(category, logger);
|
|
||||||
return logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Log(LoggerCategory loggerCategory, string message)
|
public void Log(LoggerCategory loggerCategory, string message)
|
||||||
{
|
{
|
||||||
var output = DebugService.DoFileLog
|
var output = DebugService.DoFileLog
|
||||||
? $"[{DateTime.Now.ToUniversalTime():yyyy-MM-dd HH:mm:ss}][{Enum.GetName(loggerCategory)}][{Category}]: {message}"
|
? $"[{DateTime.Now.ToUniversalTime():yyyy-MM-dd HH:mm:ss}][{Enum.GetName(loggerCategory)}][{Category}]: {message}"
|
||||||
: message;
|
: message;
|
||||||
|
|
||||||
Console.WriteLine(output);
|
|
||||||
|
|
||||||
LogToFile(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LogToFile(string output)
|
Console.WriteLine(output);
|
||||||
{
|
|
||||||
if(!DebugService.DoFileLog) return;
|
LogToFile(output);
|
||||||
_fileStream = File.Open(_path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
|
|
||||||
_streamWriter = new StreamWriter(_fileStream);
|
|
||||||
Root?.LogToFile(output);
|
|
||||||
_streamWriter.WriteLine(output);
|
|
||||||
_streamWriter.Flush();
|
|
||||||
|
|
||||||
_streamWriter.Dispose();
|
|
||||||
_fileStream.Dispose();
|
|
||||||
|
|
||||||
_fileStream = null;
|
|
||||||
_streamWriter = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (!DebugService.DoFileLog) return;
|
if (!DebugService.DoFileLog) return;
|
||||||
|
|
||||||
_streamWriter?.Dispose();
|
|
||||||
_fileStream?.Dispose();
|
|
||||||
foreach (var (_, child) in Childs)
|
foreach (var (_, child) in Childs)
|
||||||
{
|
{
|
||||||
child.Dispose();
|
child.Dispose();
|
||||||
}
|
}
|
||||||
Childs.Clear();
|
|
||||||
|
Childs.Clear(); // Not strictly necessary, but keeps intent clear
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceLogger GetLogger(string category)
|
||||||
|
{
|
||||||
|
return Childs.GetOrAdd(category, key =>
|
||||||
|
{
|
||||||
|
var logger = new ServiceLogger(key, _directory)
|
||||||
|
{
|
||||||
|
Root = this
|
||||||
|
};
|
||||||
|
return logger;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LogToFile(string output)
|
||||||
|
{
|
||||||
|
if (!DebugService.DoFileLog) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Root?.LogToFile(output); // Log to parent first
|
||||||
|
|
||||||
|
using var fileStream = File.Open(_path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
|
||||||
|
using var streamWriter = new StreamWriter(fileStream);
|
||||||
|
streamWriter.WriteLine(output);
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[Logging Error] Failed to write log: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class LoggerExtensions
|
public static class LoggerExtensions
|
||||||
{
|
{
|
||||||
public static void Debug(this ILogger logger,string message)
|
public static void Debug(this ILogger logger, string message)
|
||||||
{
|
{
|
||||||
logger.Log(LoggerCategory.Debug, message);
|
logger.Log(LoggerCategory.Debug, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Error(this ILogger logger,string message)
|
public static void Error(this ILogger logger, string message)
|
||||||
{
|
{
|
||||||
logger.Log(LoggerCategory.Error, message);
|
logger.Log(LoggerCategory.Error, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Log(this ILogger logger,string message)
|
public static void Log(this ILogger logger, string message)
|
||||||
{
|
{
|
||||||
logger.Log(LoggerCategory.Log, message);
|
logger.Log(LoggerCategory.Log, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Error(this ILogger logger,Exception e)
|
public static void Error(this ILogger logger, Exception e)
|
||||||
{
|
{
|
||||||
Error(logger,e.Message + "\r\n" + e.StackTrace);
|
Error(logger, e.Message + "\r\n" + e.StackTrace);
|
||||||
if (e.InnerException != null)
|
if (e.InnerException != null)
|
||||||
Error(logger, e.InnerException);
|
Error(logger, e.InnerException);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user