Skip to content
This repository has been archived by the owner on Jan 18, 2022. It is now read-only.

Commit

Permalink
refactor ResourceManager (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
LeNitrous authored Oct 9, 2021
1 parent 1eaa670 commit cc56f53
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/Akihabara/Native/Util/SafeResourceUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ namespace Akihabara.Native.Util
{
public partial class SafeNativeMethods : NativeMethods
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate string PathResolver(string path);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool ResourceProvider(string path, IntPtr output);

[DllImport(MediaPipeLibrary, ExactSpelling = true)]
Expand Down
64 changes: 55 additions & 9 deletions src/Akihabara/Util/ResourceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,76 @@
// See the LICENSE file in the repository root for more details.

using System;
using System.IO;
using Akihabara.External;
using static Akihabara.Native.Util.SafeNativeMethods;

namespace Akihabara.Util
{
/// <summary>
/// A class that handles resolving paths and obtaining resources for Mediapipe.
/// </summary>
/// <remarks>There should only be one instance of <see cref="ResourceManager"/> in the entire lifespan of an application.</remarks>
public abstract class ResourceManager
{
public abstract PathResolver PathResolver { get; }

public abstract ResourceProvider ResourceProvider { get; }

private static readonly object initLock = new object();
private static bool isInitialized = false;
private static ResourceManager instance;
private static PathResolver pathResolver;
private static ResourceProvider resourceProvider;

public ResourceManager() : base()
{
lock (initLock)
{
if (isInitialized)
if (instance != null)
throw new InvalidOperationException($"{nameof(ResourceManager)} can only be initialized once.");

mp__SetCustomGlobalPathResolver__P(PathResolver);
mp__SetCustomGlobalResourceProvider__P(ResourceProvider);
// Hold instances in a variable to prevent garbage collection from cleaning it.
pathResolver = resolvePath;
resourceProvider = getResource;

mp__SetCustomGlobalPathResolver__P(pathResolver);
mp__SetCustomGlobalResourceProvider__P(resourceProvider);

instance = this;
}
}

/// <summary>
/// Resolves a string path from Mediapipe to be used by <see cref="GetResource(string)"/>
/// </summary>
/// <param name="path">The path passed by Mediapipe.</param>
/// <returns>The resolved path.</returns>
protected abstract string ResolvePath(string path);

/// <summary>
/// Gets the resource as a <see cref="Stream"/> to be passed to Mediapipe.
/// </summary>
/// <param name="path">The path to the resource.</param>
/// <returns>The stream containing data to be passed to Mediapipe.</returns>
protected abstract Stream GetResource(string path);

isInitialized = true;
private static string resolvePath(string path) => instance.ResolvePath(path);

private static bool getResource(string path, IntPtr dest)
{
try
{
string resolved = instance.ResolvePath(path);
var resource = instance.GetResource(resolved);

using var memory = new MemoryStream();
resource.CopyTo(memory);

using var source = new StdString(memory.ToArray());
source.Swap(new StdString(dest, false));

return true;
}
catch (Exception)
{
// TODO: Handle errors
return false;
}
}
}
Expand Down

0 comments on commit cc56f53

Please sign in to comment.