mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Update lr client and LocationResolverSet
This commit is contained in:
parent
6db134cae4
commit
9a97e5ef3e
6 changed files with 286 additions and 172 deletions
|
@ -5,14 +5,44 @@ using LibHac.Fs;
|
||||||
using LibHac.Lr;
|
using LibHac.Lr;
|
||||||
using LibHac.Ncm;
|
using LibHac.Ncm;
|
||||||
using LibHac.Os;
|
using LibHac.Os;
|
||||||
using Path = LibHac.Lr.Path;
|
|
||||||
|
|
||||||
namespace LibHac.FsSrv.Impl
|
namespace LibHac.FsSrv.Impl
|
||||||
{
|
{
|
||||||
|
public static class LocationResolverSetGlobalMethods
|
||||||
|
{
|
||||||
|
public static void InitializeLocationResolverSet(this FileSystemServer fsSrv)
|
||||||
|
{
|
||||||
|
ref LocationResolverSetGlobals globals = ref fsSrv.Globals.LocationResolverSet;
|
||||||
|
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref globals.Mutex);
|
||||||
|
|
||||||
|
if (!globals.IsLrInitialized)
|
||||||
|
{
|
||||||
|
fsSrv.Hos.Lr.Initialize();
|
||||||
|
globals.IsLrInitialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal struct LocationResolverSetGlobals
|
||||||
|
{
|
||||||
|
public SdkMutexType Mutex;
|
||||||
|
public bool IsLrInitialized;
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
Mutex.Initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manages resolving the location of NCAs via the <c>lr</c> service.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
|
||||||
internal class LocationResolverSet : IDisposable
|
internal class LocationResolverSet : IDisposable
|
||||||
{
|
{
|
||||||
private const int LocationResolverCount = 5;
|
private const int LocationResolverCount = 5;
|
||||||
|
|
||||||
|
// Todo: Use Optional<T>
|
||||||
private LocationResolver[] _resolvers;
|
private LocationResolver[] _resolvers;
|
||||||
private AddOnContentLocationResolver _aocResolver;
|
private AddOnContentLocationResolver _aocResolver;
|
||||||
private SdkMutexType _mutex;
|
private SdkMutexType _mutex;
|
||||||
|
@ -27,16 +57,49 @@ namespace LibHac.FsSrv.Impl
|
||||||
_fsServer = fsServer;
|
_fsServer = fsServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (LocationResolver resolver in _resolvers)
|
||||||
|
{
|
||||||
|
resolver?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_aocResolver?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result SetUpFsPath(ref Fs.Path outPath, in Lr.Path lrPath)
|
||||||
|
{
|
||||||
|
var pathFlags = new PathFlags();
|
||||||
|
pathFlags.AllowMountName();
|
||||||
|
|
||||||
|
if (Utility.IsHostFsMountName(lrPath.Str))
|
||||||
|
pathFlags.AllowWindowsPath();
|
||||||
|
|
||||||
|
Result rc = outPath.InitializeWithReplaceUnc(lrPath.Str);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = outPath.Normalize(pathFlags);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
private Result GetLocationResolver(out LocationResolver resolver, StorageId storageId)
|
private Result GetLocationResolver(out LocationResolver resolver, StorageId storageId)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out resolver);
|
UnsafeHelpers.SkipParamInit(out resolver);
|
||||||
|
|
||||||
|
_fsServer.InitializeLocationResolverSet();
|
||||||
|
|
||||||
if (!IsValidStorageId(storageId))
|
if (!IsValidStorageId(storageId))
|
||||||
return ResultLr.LocationResolverNotFound.Log();
|
return ResultLr.LocationResolverNotFound.Log();
|
||||||
|
|
||||||
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _mutex);
|
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _mutex);
|
||||||
|
|
||||||
int index = GetResolverIndexFromStorageId(storageId);
|
int index = GetResolverIndexFromStorageId(storageId);
|
||||||
|
|
||||||
|
if (index < 0)
|
||||||
|
return ResultLr.LocationResolverNotFound.Log();
|
||||||
|
|
||||||
ref LocationResolver lr = ref _resolvers[index];
|
ref LocationResolver lr = ref _resolvers[index];
|
||||||
|
|
||||||
// Open the location resolver if it hasn't been already
|
// Open the location resolver if it hasn't been already
|
||||||
|
@ -64,6 +127,8 @@ namespace LibHac.FsSrv.Impl
|
||||||
|
|
||||||
private Result GetAddOnContentLocationResolver(out AddOnContentLocationResolver resolver)
|
private Result GetAddOnContentLocationResolver(out AddOnContentLocationResolver resolver)
|
||||||
{
|
{
|
||||||
|
_fsServer.InitializeLocationResolverSet();
|
||||||
|
|
||||||
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _mutex);
|
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _mutex);
|
||||||
|
|
||||||
if (_aocResolver is null)
|
if (_aocResolver is null)
|
||||||
|
@ -82,108 +147,126 @@ namespace LibHac.FsSrv.Impl
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result ResolveApplicationControlPath(out Path path, Ncm.ApplicationId applicationId, StorageId storageId)
|
public Result ResolveApplicationControlPath(ref Fs.Path outPath, Ncm.ApplicationId applicationId, StorageId storageId)
|
||||||
{
|
{
|
||||||
Path.InitEmpty(out path);
|
Result rc = GetLocationResolver(out LocationResolver resolver, storageId);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = resolver.ResolveApplicationControlPath(out Lr.Path path, applicationId);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
return SetUpFsPath(ref outPath, in path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result ResolveApplicationHtmlDocumentPath(out bool isDirectory, ref Fs.Path outPath, Ncm.ApplicationId applicationId, StorageId storageId)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out isDirectory);
|
||||||
|
|
||||||
Result rc = GetLocationResolver(out LocationResolver resolver, storageId);
|
Result rc = GetLocationResolver(out LocationResolver resolver, storageId);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = resolver.ResolveApplicationControlPath(out path, applicationId);
|
rc = resolver.ResolveApplicationHtmlDocumentPath(out Lr.Path path, applicationId);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
PathUtility.Replace(path.StrMutable, (byte)'\\', (byte)'/');
|
isDirectory = PathUtility12.IsDirectoryPath(path.Str);
|
||||||
return Result.Success;
|
|
||||||
|
return SetUpFsPath(ref outPath, in path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result ResolveApplicationHtmlDocumentPath(out Path path, Ncm.ApplicationId applicationId, StorageId storageId)
|
public Result ResolveProgramPath(out bool isDirectory, ref Fs.Path outPath, ProgramId programId, StorageId storageId)
|
||||||
{
|
{
|
||||||
Path.InitEmpty(out path);
|
UnsafeHelpers.SkipParamInit(out isDirectory);
|
||||||
|
|
||||||
Result rc = GetLocationResolver(out LocationResolver resolver, storageId);
|
Result rc = GetLocationResolver(out LocationResolver resolver, storageId);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = resolver.ResolveApplicationHtmlDocumentPath(out path, applicationId);
|
rc = resolver.ResolveProgramPath(out Lr.Path path, programId);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
PathUtility.Replace(path.StrMutable, (byte)'\\', (byte)'/');
|
isDirectory = PathUtility12.IsDirectoryPath(path.Str);
|
||||||
return Result.Success;
|
|
||||||
|
return SetUpFsPath(ref outPath, in path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Result ResolveProgramPath(out Path path, ulong id, StorageId storageId)
|
public Result ResolveRomPath(out bool isDirectory, ref Fs.Path outPath, ProgramId programId, StorageId storageId)
|
||||||
{
|
{
|
||||||
Path.InitEmpty(out path);
|
UnsafeHelpers.SkipParamInit(out isDirectory);
|
||||||
|
|
||||||
Result rc = GetLocationResolver(out LocationResolver resolver, storageId);
|
Result rc = GetLocationResolver(out LocationResolver resolver, storageId);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
rc = resolver.ResolveProgramPath(out path, new ProgramId(id));
|
rc = resolver.ResolveProgramPathForDebug(out Lr.Path path, programId);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
PathUtility.Replace(path.StrMutable, (byte)'\\', (byte)'/');
|
isDirectory = PathUtility12.IsDirectoryPath(path.Str);
|
||||||
return Result.Success;
|
|
||||||
|
return SetUpFsPath(ref outPath, in path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result ResolveRomPath(out Path path, ulong id, StorageId storageId)
|
public Result ResolveAddOnContentPath(ref Fs.Path outPath, DataId dataId)
|
||||||
{
|
{
|
||||||
Path.InitEmpty(out path);
|
|
||||||
|
|
||||||
Result rc = GetLocationResolver(out LocationResolver resolver, storageId);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
rc = resolver.ResolveProgramPath(out path, new ProgramId(id));
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
PathUtility.Replace(path.StrMutable, (byte)'\\', (byte)'/');
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result ResolveAddOnContentPath(out Path path, DataId dataId)
|
|
||||||
{
|
|
||||||
Path.InitEmpty(out path);
|
|
||||||
|
|
||||||
Result rc = GetAddOnContentLocationResolver(out AddOnContentLocationResolver resolver);
|
Result rc = GetAddOnContentLocationResolver(out AddOnContentLocationResolver resolver);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return resolver.ResolveAddOnContentPath(out path, dataId);
|
rc = resolver.ResolveAddOnContentPath(out Lr.Path path, dataId);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
return SetUpFsPath(ref outPath, in path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result ResolveDataPath(out Path path, DataId dataId, StorageId storageId)
|
public Result ResolveDataPath(ref Fs.Path outPath, DataId dataId, StorageId storageId)
|
||||||
{
|
{
|
||||||
Path.InitEmpty(out path);
|
|
||||||
|
|
||||||
if (storageId == StorageId.None)
|
if (storageId == StorageId.None)
|
||||||
return ResultFs.InvalidAlignment.Log();
|
return ResultFs.InvalidAlignment.Log();
|
||||||
|
|
||||||
Result rc = GetLocationResolver(out LocationResolver resolver, storageId);
|
Result rc = GetLocationResolver(out LocationResolver resolver, storageId);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
return resolver.ResolveDataPath(out path, dataId);
|
rc = resolver.ResolveDataPath(out Lr.Path path, dataId);
|
||||||
}
|
|
||||||
|
|
||||||
public Result ResolveRegisteredProgramPath(out Path path, ulong id)
|
|
||||||
{
|
|
||||||
Path.InitEmpty(out path);
|
|
||||||
|
|
||||||
Result rc = GetRegisteredLocationResolver(out RegisteredLocationResolver resolver);
|
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
using (resolver)
|
return SetUpFsPath(ref outPath, in path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result ResolveRegisteredProgramPath(ref Fs.Path outPath, ulong id)
|
||||||
|
{
|
||||||
|
_fsServer.InitializeLocationResolverSet();
|
||||||
|
|
||||||
|
RegisteredLocationResolver resolver = null;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return resolver.ResolveProgramPath(out path, new ProgramId(id));
|
Result rc = GetRegisteredLocationResolver(out resolver);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = resolver.ResolveProgramPath(out Lr.Path path, new ProgramId(id));
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
return SetUpFsPath(ref outPath, in path);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
resolver?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result ResolveRegisteredHtmlDocumentPath(out Path path, ulong id)
|
public Result ResolveRegisteredHtmlDocumentPath(ref Fs.Path outPath, ulong id)
|
||||||
{
|
{
|
||||||
Path.InitEmpty(out path);
|
_fsServer.InitializeLocationResolverSet();
|
||||||
|
|
||||||
Result rc = GetRegisteredLocationResolver(out RegisteredLocationResolver resolver);
|
RegisteredLocationResolver resolver = null;
|
||||||
if (rc.IsFailure()) return rc;
|
try
|
||||||
|
|
||||||
using (resolver)
|
|
||||||
{
|
{
|
||||||
return resolver.ResolveHtmlDocumentPath(out path, new ProgramId(id));
|
Result rc = GetRegisteredLocationResolver(out resolver);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = resolver.ResolveHtmlDocumentPath(out Lr.Path path, new ProgramId(id));
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
return SetUpFsPath(ref outPath, in path);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
resolver?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,15 +293,5 @@ namespace LibHac.FsSrv.Impl
|
||||||
_ => -1
|
_ => -1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
foreach (LocationResolver resolver in _resolvers)
|
|
||||||
{
|
|
||||||
resolver?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_aocResolver?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Ncm;
|
using LibHac.Ncm;
|
||||||
using LibHac.Sf;
|
using LibHac.Sf;
|
||||||
|
|
||||||
|
@ -8,9 +9,14 @@ namespace LibHac.Lr
|
||||||
{
|
{
|
||||||
private ReferenceCountedDisposable<IAddOnContentLocationResolver> _interface;
|
private ReferenceCountedDisposable<IAddOnContentLocationResolver> _interface;
|
||||||
|
|
||||||
public AddOnContentLocationResolver(ReferenceCountedDisposable<IAddOnContentLocationResolver> baseInterface)
|
public AddOnContentLocationResolver(ref ReferenceCountedDisposable<IAddOnContentLocationResolver> baseInterface)
|
||||||
{
|
{
|
||||||
_interface = baseInterface.AddReference();
|
_interface = Shared.Move(ref baseInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_interface?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result ResolveAddOnContentPath(out Path path, DataId id) =>
|
public Result ResolveAddOnContentPath(out Path path, DataId id) =>
|
||||||
|
@ -27,10 +33,5 @@ namespace LibHac.Lr
|
||||||
|
|
||||||
public Result UnregisterApplicationAddOnContent(Ncm.ApplicationId id) =>
|
public Result UnregisterApplicationAddOnContent(Ncm.ApplicationId id) =>
|
||||||
_interface.Target.UnregisterApplicationAddOnContent(id);
|
_interface.Target.UnregisterApplicationAddOnContent(id);
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_interface?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Ncm;
|
using LibHac.Ncm;
|
||||||
using LibHac.Sf;
|
using LibHac.Sf;
|
||||||
|
|
||||||
|
@ -8,9 +9,14 @@ namespace LibHac.Lr
|
||||||
{
|
{
|
||||||
private ReferenceCountedDisposable<ILocationResolver> _interface;
|
private ReferenceCountedDisposable<ILocationResolver> _interface;
|
||||||
|
|
||||||
public LocationResolver(ReferenceCountedDisposable<ILocationResolver> baseInterface)
|
public LocationResolver(ref ReferenceCountedDisposable<ILocationResolver> baseInterface)
|
||||||
{
|
{
|
||||||
_interface = baseInterface.AddReference();
|
_interface = Shared.Move(ref baseInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_interface?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result ResolveProgramPath(out Path path, ProgramId id) =>
|
public Result ResolveProgramPath(out Path path, ProgramId id) =>
|
||||||
|
@ -72,10 +78,5 @@ namespace LibHac.Lr
|
||||||
|
|
||||||
public Result EraseProgramRedirectionForDebug(ProgramId id) =>
|
public Result EraseProgramRedirectionForDebug(ProgramId id) =>
|
||||||
_interface.Target.EraseProgramRedirectionForDebug(id);
|
_interface.Target.EraseProgramRedirectionForDebug(id);
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_interface?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,103 +1,37 @@
|
||||||
using System;
|
using System;
|
||||||
using LibHac.Common;
|
|
||||||
using LibHac.Ncm;
|
|
||||||
|
|
||||||
namespace LibHac.Lr
|
namespace LibHac.Lr
|
||||||
{
|
{
|
||||||
public class LrClient : IDisposable
|
public class LrClient : IDisposable
|
||||||
{
|
{
|
||||||
private HorizonClient Hos { get; }
|
internal LrClientGlobals Globals;
|
||||||
|
internal HorizonClient Hos => Globals.Hos;
|
||||||
private ILocationResolverManager LrManager { get; set; }
|
|
||||||
private readonly object _lrInitLocker = new object();
|
|
||||||
|
|
||||||
public LrClient(HorizonClient horizonClient)
|
public LrClient(HorizonClient horizonClient)
|
||||||
{
|
{
|
||||||
Hos = horizonClient;
|
Globals.Initialize(this, horizonClient);
|
||||||
}
|
|
||||||
|
|
||||||
public Result OpenLocationResolver(out LocationResolver resolver, StorageId storageId)
|
|
||||||
{
|
|
||||||
UnsafeHelpers.SkipParamInit(out resolver);
|
|
||||||
EnsureInitialized();
|
|
||||||
|
|
||||||
Result rc = LrManager.OpenLocationResolver(out ReferenceCountedDisposable<ILocationResolver> baseResolver,
|
|
||||||
storageId);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
using (baseResolver)
|
|
||||||
{
|
|
||||||
resolver = new LocationResolver(baseResolver);
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result OpenRegisteredLocationResolver(out RegisteredLocationResolver resolver)
|
|
||||||
{
|
|
||||||
UnsafeHelpers.SkipParamInit(out resolver);
|
|
||||||
EnsureInitialized();
|
|
||||||
|
|
||||||
Result rc = LrManager.OpenRegisteredLocationResolver(
|
|
||||||
out ReferenceCountedDisposable<IRegisteredLocationResolver> baseResolver);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
using (baseResolver)
|
|
||||||
{
|
|
||||||
resolver = new RegisteredLocationResolver(baseResolver);
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result OpenAddOnContentLocationResolver(out AddOnContentLocationResolver resolver)
|
|
||||||
{
|
|
||||||
UnsafeHelpers.SkipParamInit(out resolver);
|
|
||||||
EnsureInitialized();
|
|
||||||
|
|
||||||
Result rc = LrManager.OpenAddOnContentLocationResolver(
|
|
||||||
out ReferenceCountedDisposable<IAddOnContentLocationResolver> baseResolver);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
using (baseResolver)
|
|
||||||
{
|
|
||||||
resolver = new AddOnContentLocationResolver(baseResolver);
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result RefreshLocationResolver(StorageId storageId)
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
|
|
||||||
Result rc = LrManager.RefreshLocationResolver(storageId);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureInitialized()
|
|
||||||
{
|
|
||||||
if (LrManager != null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock (_lrInitLocker)
|
|
||||||
{
|
|
||||||
if (LrManager != null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Result rc = Hos.Sm.GetService(out ILocationResolverManager manager, "lr");
|
|
||||||
|
|
||||||
if (rc.IsFailure())
|
|
||||||
{
|
|
||||||
throw new HorizonResultException(rc, "Failed to initialize lr client.");
|
|
||||||
}
|
|
||||||
|
|
||||||
LrManager = manager;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
LrManager?.Dispose();
|
Globals.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal struct LrClientGlobals
|
||||||
|
{
|
||||||
|
public HorizonClient Hos;
|
||||||
|
public LrServiceGlobals LrService;
|
||||||
|
|
||||||
|
public void Initialize(LrClient lrClient, HorizonClient horizonClient)
|
||||||
|
{
|
||||||
|
Hos = horizonClient;
|
||||||
|
LrService.Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
LrService.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
104
src/LibHac/Lr/LrService.cs
Normal file
104
src/LibHac/Lr/LrService.cs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Diag;
|
||||||
|
using LibHac.Ncm;
|
||||||
|
using LibHac.Os;
|
||||||
|
|
||||||
|
namespace LibHac.Lr
|
||||||
|
{
|
||||||
|
internal struct LrServiceGlobals
|
||||||
|
{
|
||||||
|
public ILocationResolverManager LocationResolver;
|
||||||
|
public SdkMutex InitializationMutex;
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
LocationResolver = null;
|
||||||
|
InitializationMutex.Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (LocationResolver is not null)
|
||||||
|
{
|
||||||
|
LocationResolver.Dispose();
|
||||||
|
LocationResolver = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LrService
|
||||||
|
{
|
||||||
|
public static void Initialize(this LrClient lr)
|
||||||
|
{
|
||||||
|
ref LrServiceGlobals globals = ref lr.Globals.LrService;
|
||||||
|
Assert.SdkRequiresNotNull(globals.LocationResolver);
|
||||||
|
|
||||||
|
// The lock over getting the service object is a LibHac addition.
|
||||||
|
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref lr.Globals.LrService.InitializationMutex);
|
||||||
|
|
||||||
|
if (globals.LocationResolver is not null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ILocationResolverManager serviceObject = lr.GetLocationResolverManagerServiceObject();
|
||||||
|
globals.LocationResolver = serviceObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result OpenLocationResolver(this LrClient lr, out LocationResolver resolver, StorageId storageId)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out resolver);
|
||||||
|
|
||||||
|
Result rc = lr.Globals.LrService.LocationResolver.OpenLocationResolver(
|
||||||
|
out ReferenceCountedDisposable<ILocationResolver> baseResolver, storageId);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
resolver = new LocationResolver(ref baseResolver);
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result OpenRegisteredLocationResolver(this LrClient lr, out RegisteredLocationResolver resolver)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out resolver);
|
||||||
|
|
||||||
|
Result rc = lr.Globals.LrService.LocationResolver.OpenRegisteredLocationResolver(
|
||||||
|
out ReferenceCountedDisposable<IRegisteredLocationResolver> baseResolver);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
resolver = new RegisteredLocationResolver(ref baseResolver);
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result OpenAddOnContentLocationResolver(this LrClient lr, out AddOnContentLocationResolver resolver)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out resolver);
|
||||||
|
|
||||||
|
Result rc = lr.Globals.LrService.LocationResolver.OpenAddOnContentLocationResolver(
|
||||||
|
out ReferenceCountedDisposable<IAddOnContentLocationResolver> baseResolver);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
resolver = new AddOnContentLocationResolver(ref baseResolver);
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result RefreshLocationResolver(this LrClient lr, StorageId storageId)
|
||||||
|
{
|
||||||
|
Result rc = lr.Globals.LrService.LocationResolver.RefreshLocationResolver(storageId);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Official lr puts this function along with memory allocation for
|
||||||
|
// lr IPC objects into a separate file, LocationResolverManagerFactory.
|
||||||
|
private static ILocationResolverManager GetLocationResolverManagerServiceObject(this LrClient lr)
|
||||||
|
{
|
||||||
|
Result rc = lr.Hos.Sm.GetService(out ILocationResolverManager manager, "lr");
|
||||||
|
|
||||||
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
throw new HorizonResultException(rc, "Failed to get lr service object.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Ncm;
|
using LibHac.Ncm;
|
||||||
|
|
||||||
namespace LibHac.Lr
|
namespace LibHac.Lr
|
||||||
|
@ -7,9 +8,14 @@ namespace LibHac.Lr
|
||||||
{
|
{
|
||||||
private ReferenceCountedDisposable<IRegisteredLocationResolver> _interface;
|
private ReferenceCountedDisposable<IRegisteredLocationResolver> _interface;
|
||||||
|
|
||||||
public RegisteredLocationResolver(ReferenceCountedDisposable<IRegisteredLocationResolver> baseInterface)
|
public RegisteredLocationResolver(ref ReferenceCountedDisposable<IRegisteredLocationResolver> baseInterface)
|
||||||
{
|
{
|
||||||
_interface = baseInterface.AddReference();
|
_interface = Shared.Move(ref baseInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_interface?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result ResolveProgramPath(out Path path, ProgramId id) =>
|
public Result ResolveProgramPath(out Path path, ProgramId id) =>
|
||||||
|
@ -41,10 +47,5 @@ namespace LibHac.Lr
|
||||||
|
|
||||||
public Result RefreshExcluding(ReadOnlySpan<ProgramId> ids) =>
|
public Result RefreshExcluding(ReadOnlySpan<ProgramId> ids) =>
|
||||||
_interface.Target.RefreshExcluding(ids);
|
_interface.Target.RefreshExcluding(ids);
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_interface?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue