- tweak: Change content running logic
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ProcessHelper;
|
||||
|
||||
public abstract class DotnetProcessStartInfoProviderBase(DotnetResolverService resolverService) : IProcessStartInfoProvider
|
||||
{
|
||||
protected abstract string GetDllPath();
|
||||
|
||||
public virtual async Task<ProcessStartInfo> GetProcessStartInfo()
|
||||
{
|
||||
return new ProcessStartInfo
|
||||
{
|
||||
FileName = await resolverService.EnsureDotnet(),
|
||||
Arguments = GetDllPath(),
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
StandardOutputEncoding = Encoding.UTF8
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Nebula.Shared;
|
||||
using Nebula.Shared.Models;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ProcessHelper;
|
||||
|
||||
[ServiceRegister(isSingleton:false)]
|
||||
public sealed class GameProcessStartInfoProvider(DotnetResolverService resolverService, AuthService authService) :
|
||||
DotnetProcessStartInfoProviderBase(resolverService)
|
||||
{
|
||||
private string? _publicKey;
|
||||
private RobustUrl _address = default!;
|
||||
|
||||
protected override string GetDllPath()
|
||||
{
|
||||
var path = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||
return Path.Join(path, "Nebula.Runner.dll");
|
||||
}
|
||||
|
||||
public GameProcessStartInfoProvider WithBuildInfo(string publicKey, RobustUrl address)
|
||||
{
|
||||
_publicKey = publicKey;
|
||||
_address = address;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public override async Task<ProcessStartInfo> GetProcessStartInfo()
|
||||
{
|
||||
var baseStart = await base.GetProcessStartInfo();
|
||||
|
||||
var authProv = authService.SelectedAuth;
|
||||
if(authProv is null)
|
||||
throw new Exception("Client is without selected auth");
|
||||
|
||||
baseStart.EnvironmentVariables["ROBUST_AUTH_USERID"] = authProv.UserId.ToString();
|
||||
baseStart.EnvironmentVariables["ROBUST_AUTH_TOKEN"] = authProv.Token.Token;
|
||||
baseStart.EnvironmentVariables["ROBUST_AUTH_SERVER"] = authProv.AuthServer;
|
||||
baseStart.EnvironmentVariables["AUTH_LOGIN"] = authProv.Login;
|
||||
baseStart.EnvironmentVariables["ROBUST_AUTH_PUBKEY"] = _publicKey;
|
||||
baseStart.EnvironmentVariables["GAME_URL"] = _address.ToString();
|
||||
|
||||
return baseStart;
|
||||
}
|
||||
}
|
||||
33
Nebula.Launcher/ProcessHelper/GameRunnerPreparer.cs
Normal file
33
Nebula.Launcher/ProcessHelper/GameRunnerPreparer.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Nebula.Shared;
|
||||
using Nebula.Shared.Models;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ProcessHelper;
|
||||
|
||||
[ServiceRegister]
|
||||
public sealed class GameRunnerPreparer(IServiceProvider provider, ContentService contentService, EngineService engineService, DebugService debugService)
|
||||
{
|
||||
public async Task<ProcessRunHandler<GameProcessStartInfoProvider>> GetGameProcessStartInfoProvider(RobustUrl address, ILoadingHandler loadingHandler, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var buildInfo = await contentService.GetBuildInfo(address, cancellationToken);
|
||||
|
||||
var engine = await engineService.EnsureEngine(buildInfo.BuildInfo.Build.EngineVersion);
|
||||
|
||||
if (engine is null)
|
||||
throw new Exception("Engine version not found: " + buildInfo.BuildInfo.Build.EngineVersion);
|
||||
|
||||
await contentService.EnsureItems(buildInfo.RobustManifestInfo, loadingHandler, cancellationToken);
|
||||
await engineService.EnsureEngineModules("Robust.Client.WebView", buildInfo.BuildInfo.Build.EngineVersion);
|
||||
|
||||
var gameInfo =
|
||||
provider.GetService<GameProcessStartInfoProvider>()!.WithBuildInfo(buildInfo.BuildInfo.Auth.PublicKey,
|
||||
address);
|
||||
var gameProcessRunHandler = new ProcessRunHandler<GameProcessStartInfoProvider>(gameInfo);
|
||||
|
||||
return gameProcessRunHandler;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Nebula.Launcher.ProcessHelper;
|
||||
|
||||
public interface IProcessConsumerCollection
|
||||
{
|
||||
public void RegisterLogger(IProcessLogConsumer consumer);
|
||||
}
|
||||
8
Nebula.Launcher/ProcessHelper/IProcessLogConsumer.cs
Normal file
8
Nebula.Launcher/ProcessHelper/IProcessLogConsumer.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Nebula.Launcher.ProcessHelper;
|
||||
|
||||
public interface IProcessLogConsumer
|
||||
{
|
||||
public void Out(string text);
|
||||
public void Error(string text);
|
||||
public void Fatal(string text);
|
||||
}
|
||||
9
Nebula.Launcher/ProcessHelper/IProcessRunner.cs
Normal file
9
Nebula.Launcher/ProcessHelper/IProcessRunner.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nebula.Launcher.ProcessHelper;
|
||||
|
||||
public interface IProcessStartInfoProvider
|
||||
{
|
||||
public Task<ProcessStartInfo> GetProcessStartInfo();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Nebula.Launcher.ProcessHelper;
|
||||
|
||||
public sealed class ProcessLogConsumerCollection: IProcessLogConsumer, IProcessConsumerCollection
|
||||
{
|
||||
private readonly List<IProcessLogConsumer> _consumers = [];
|
||||
|
||||
public void RegisterLogger(IProcessLogConsumer consumer)
|
||||
{
|
||||
_consumers.Add(consumer);
|
||||
}
|
||||
|
||||
public void Out(string text)
|
||||
{
|
||||
foreach (var consumer in _consumers)
|
||||
{
|
||||
consumer.Out(text);
|
||||
}
|
||||
}
|
||||
|
||||
public void Error(string text)
|
||||
{
|
||||
foreach (var consumer in _consumers)
|
||||
{
|
||||
consumer.Error(text);
|
||||
}
|
||||
}
|
||||
|
||||
public void Fatal(string text)
|
||||
{
|
||||
foreach (var consumer in _consumers)
|
||||
{
|
||||
consumer.Fatal(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
137
Nebula.Launcher/ProcessHelper/ProcessRunHandler.cs
Normal file
137
Nebula.Launcher/ProcessHelper/ProcessRunHandler.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Nebula.Shared.Services;
|
||||
using Nebula.Shared.Services.Logging;
|
||||
|
||||
namespace Nebula.Launcher.ProcessHelper;
|
||||
|
||||
public class ProcessRunHandler<T> : IProcessConsumerCollection, IDisposable where T: IProcessStartInfoProvider
|
||||
{
|
||||
private ProcessStartInfo? _processInfo;
|
||||
private Task<ProcessStartInfo>? _processInfoTask;
|
||||
|
||||
private Process? _process;
|
||||
private ProcessLogConsumerCollection _consumerCollection = new();
|
||||
|
||||
private string _lastError = string.Empty;
|
||||
private readonly T _currentProcessStartInfoProvider;
|
||||
|
||||
public T GetCurrentProcessStartInfo() => _currentProcessStartInfoProvider;
|
||||
public bool IsRunning => _processInfo is not null;
|
||||
public Action<ProcessRunHandler<T>>? OnProcessExited;
|
||||
|
||||
public void RegisterLogger(IProcessLogConsumer consumer)
|
||||
{
|
||||
_consumerCollection.RegisterLogger(consumer);
|
||||
}
|
||||
|
||||
public ProcessRunHandler(T processStartInfoProvider)
|
||||
{
|
||||
_currentProcessStartInfoProvider = processStartInfoProvider;
|
||||
_processInfoTask = _currentProcessStartInfoProvider.GetProcessStartInfo();
|
||||
_processInfoTask.GetAwaiter().OnCompleted(OnInfoProvided);
|
||||
}
|
||||
|
||||
private void OnInfoProvided()
|
||||
{
|
||||
if (_processInfoTask == null)
|
||||
return;
|
||||
|
||||
_processInfo = _processInfoTask.GetAwaiter().GetResult();
|
||||
_processInfoTask = null;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (_processInfoTask != null)
|
||||
{
|
||||
_processInfoTask.Wait();
|
||||
}
|
||||
|
||||
_process = Process.Start(_processInfo!);
|
||||
|
||||
if (_process is null) return;
|
||||
|
||||
_process.EnableRaisingEvents = true;
|
||||
|
||||
_process.BeginOutputReadLine();
|
||||
_process.BeginErrorReadLine();
|
||||
|
||||
_process.OutputDataReceived += OnOutputDataReceived;
|
||||
_process.ErrorDataReceived += OnErrorDataReceived;
|
||||
|
||||
_process.Exited += OnExited;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_process?.CloseMainWindow();
|
||||
}
|
||||
|
||||
private void OnExited(object? sender, EventArgs e)
|
||||
{
|
||||
if (_process is null) return;
|
||||
|
||||
_process.OutputDataReceived -= OnOutputDataReceived;
|
||||
_process.ErrorDataReceived -= OnErrorDataReceived;
|
||||
_process.Exited -= OnExited;
|
||||
|
||||
|
||||
if (_process.ExitCode != 0)
|
||||
_consumerCollection.Fatal(_lastError);
|
||||
|
||||
_process.Dispose();
|
||||
_process = null;
|
||||
|
||||
OnProcessExited?.Invoke(this);
|
||||
}
|
||||
|
||||
private void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e.Data != null)
|
||||
{
|
||||
_lastError = e.Data;
|
||||
_consumerCollection.Error(e.Data);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e.Data != null)
|
||||
{
|
||||
_consumerCollection.Out(e.Data);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_processInfoTask?.Dispose();
|
||||
_process?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DebugLoggerBridge : IProcessLogConsumer
|
||||
{
|
||||
private ILogger _logger;
|
||||
|
||||
public DebugLoggerBridge(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Out(string text)
|
||||
{
|
||||
_logger.Log(LoggerCategory.Log, text);
|
||||
}
|
||||
|
||||
public void Error(string text)
|
||||
{
|
||||
_logger.Log(LoggerCategory.Error, text);
|
||||
}
|
||||
|
||||
public void Fatal(string text)
|
||||
{
|
||||
_logger.Log(LoggerCategory.Error, text);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user