You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Sonarr/src/Sonarr.RuntimePatches/RuntimePatchBase.cs

147 lines
4.1 KiB

using System;
using System.Collections.Generic;
using System.Reflection;
using HarmonyLib;
namespace NzbDrone.RuntimePatches
{
public abstract class RuntimePatchBase
{
private Harmony _harmony;
internal static bool IsDebug;
public virtual bool ShouldPatch() => true;
protected abstract void Patch();
public void Patch(Harmony harmony)
{
_harmony = harmony;
if (ShouldPatch())
{
Patch();
}
}
protected const BindingFlags DefaultBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
protected static MethodInfo FindMethod(Type type, string methodName, params string[] paramTypes)
{
foreach (var methodInfo in type.GetMethods(DefaultBindingFlags))
{
if (methodInfo.Name != methodName)
{
continue;
}
var parameters = methodInfo.GetParameters();
if (parameters.Length != paramTypes.Length)
{
continue;
}
var parametersMatch = true;
for (var i = 0; i < parameters.Length; i++)
{
if (parameters[i].ParameterType.Name != paramTypes[i] &&
parameters[i].ParameterType.FullName != paramTypes[i] &&
parameters[i].ParameterType.GetSimplifiedName() != paramTypes[i] &&
parameters[i].ParameterType.GetSimplifiedName(true) != paramTypes[i])
{
parametersMatch = false;
break;
}
}
if (!parametersMatch)
{
continue;
}
return methodInfo;
}
return null;
}
protected void PatchMethod(MethodInfo methodInfo)
{
var prefix = GetPatchMethod("Prefix_" + methodInfo.Name);
var postfix = GetPatchMethod("Postfix_" + methodInfo.Name);
var transpiler = GetPatchMethod("Transpiler_" + methodInfo.Name);
_harmony.Patch(methodInfo, prefix, postfix, transpiler);
}
protected void TryPatchMethod(string typeName, string methodName, params string[] paramTypes)
{
var type = Type.GetType(typeName);
if (type != null)
{
TryPatchMethod(type, "GetSslServer");
}
else
{
Debug($"Skipped patching method {typeName}.{methodName}: Type not found");
}
}
protected void TryPatchMethod(Type type, string methodName, params string[] paramTypes)
{
var methodInfo = FindMethod(type, methodName, paramTypes);
if (methodInfo != null)
{
PatchMethod(methodInfo);
}
else
{
Debug($"Skipped patching method {type.GetSimplifiedName()}.{methodName}: Method not found");
}
}
private HarmonyMethod GetPatchMethod(string name)
{
var patch = GetType().GetMethod(name, DefaultBindingFlags);
if (patch != null)
{
return new HarmonyMethod(patch);
}
return null;
}
protected void DebugOpcodes(string prefix, List<CodeInstruction> codes)
{
if (IsDebug)
{
Log($"Opcodes {prefix}:");
foreach (var code in codes)
{
Console.WriteLine($" {code}");
}
}
}
protected void Debug(string log)
{
if (IsDebug)
{
Log(log);
}
}
protected void Error(string log)
{
Log(log);
}
protected virtual void Log(string log)
{
Console.WriteLine($"RuntimePatch {GetType().Name}: {log}");
}
}
}