//
// CommsInjector.cs
//
// Copyright (c) František Boháček. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
using NosSmooth.Comms.Core;
using NosSmooth.Comms.Core.NamedPipes;
using NosSmooth.Comms.Data;
using NosSmooth.Comms.Inject;
using NosSmooth.Injector;
using NosSmooth.LocalBinding;
using NosSmooth.LocalBinding.Options;
using Remora.Results;
namespace NosSmooth.Comms.Local;
///
/// Injects communication (tcp or named pipes) into a nostale process.
///
public class CommsInjector
{
private readonly IServiceProvider _serviceProvider;
private readonly NosInjector _injector;
private readonly NostaleClientResolver _resolver;
///
/// Initializes a new instance of the class.
///
/// The service provider.
/// The injector.
/// The nostale client resolver.
public CommsInjector(IServiceProvider serviceProvider, NosInjector injector, NostaleClientResolver resolver)
{
_serviceProvider = serviceProvider;
_injector = injector;
_resolver = resolver;
}
///
/// Find processes that are NosTale and create a from them.
///
/// The names to filter when searching the processes. In case the array is empty, look for all processes.
/// A list of the NosTale processes.
public static IEnumerable> CreateNostaleProcesssesBrowsers(params string[] filterNames)
{
return FindNosTaleProcesses(filterNames)
.Select
(
x =>
{
var manager = new NosBrowserManager
(
x,
new PlayerManagerOptions(),
new SceneManagerOptions(),
new PetManagerOptions(),
new NetworkManagerOptions(),
new UnitManagerOptions()
);
var initResult = manager.Initialize();
if (!initResult.IsSuccess)
{
return Result.FromError(initResult.Error);
}
return manager;
}
);
}
///
/// Find processes that are NosTale.
///
/// The names to filter when searching the processes. In case the array is empty, look for all processes.
/// A list of the NosTale processes.
public static IEnumerable FindNosTaleProcesses(params string[] filterNames)
{
var processes = Process.GetProcesses().AsEnumerable();
if (filterNames.Length > 0)
{
processes = processes.Where(x => filterNames.Contains(x.ProcessName));
}
return processes
.Where
(
x =>
{
try
{
return NosBrowserManager.IsProcessNostaleProcess(x);
}
catch
{
return false;
}
}
);
}
///
/// Inject NosSmooth.Comms.Inject.dll into the process,
/// enable tcp server and establish a connection to the server.
///
/// The result containing information about the established connection.
public Task>
EstablishTcpConnectionAsync()
{
throw new NotImplementedException();
}
///
/// Inject NosSmooth.Comms.Inject.dll into the process,
/// enable named pipes server and establish a connection to the server.
///
/// The process to establish named pipes with.
/// The token used for stopping the connection.
/// The cancellation token used for cancelling the operation.
/// The result containing information about the established connection.
public async Task> EstablishNamedPipesConnectionAsync
(Process process, CancellationToken stopToken, CancellationToken ct)
{
var injectResult = Inject(process, nameof(DllMain.EnableNamedPipes));
if (!injectResult.IsSuccess)
{
return Result.FromError(injectResult);
}
var namedPipeClient = new NamedPipeClient($"NosSmooth_{process.Id}");
var connectionResult = await namedPipeClient.ConnectAsync(ct);
if (!connectionResult.IsSuccess)
{
return Result.FromError(connectionResult);
}
var handler = ActivatorUtilities.CreateInstance
(_serviceProvider, (IConnection)namedPipeClient);
handler.StartHandler(stopToken);
var nostaleClient = _resolver.Resolve(handler);
return new Comms(process, handler, nostaleClient);
}
///
/// Open a console in the target process.
///
///
/// Log of inject will be printed to the console.
///
/// The process.
/// A result that may or may not have succeeded.
public Result OpenConsole(Process process)
{
return Inject(process, nameof(DllMain.OpenConsole));
}
///
/// Close a console in the target process.
///
/// The process.
/// A result that may or may not have succeeded.
public Result CloseConsole(Process process)
{
return Inject(process, nameof(DllMain.CloseConsole));
}
private Result Inject(Process process, string method)
{
return _injector.Inject
(
process,
Path.GetFullPath("NosSmooth.Comms.Inject.dll"),
"NosSmooth.Comms.Inject.DllMain, NosSmooth.Comms.Inject",
method
);
}
}