-
Notifications
You must be signed in to change notification settings - Fork 2
V0.1beta #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
V0.1beta #1
Changes from all commits
acab2e9
c3a13f7
16bee6f
d713f90
2b6c287
0c16754
6186cf5
e2b7093
79edeac
7ac5977
6546120
aa1dae8
e02eb1a
2308892
be1266d
b6760b6
32ed3db
f553100
de701e0
28a3cd4
d23bf34
4380931
ef42892
c79e4eb
6583cea
21ad902
2545927
ff24548
b27a050
926300c
e4b36f9
bf0dd61
b2ae2f0
65ded2b
5af64f6
cdd8af5
b154db3
58807b3
d00dc95
9caefa1
9206070
89f0819
ca369d3
51888af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,173 +2,106 @@ | |
| using System.Collections.Concurrent; | ||
| using System.IO; | ||
| using System.Runtime.InteropServices; | ||
| using FreeSWITCH; | ||
| using PluginInterface; | ||
| using FreeSWITCH.Helpers; | ||
| using System.Reflection; | ||
|
|
||
| namespace FreeSWITCH | ||
| { | ||
| public static class Loader | ||
| { | ||
| // The primary entry point delegate for obtaining the native callbacks during host initialization | ||
| // The primary entry point delegate for obtaining the native callbacks during host initialization | ||
| private delegate NativeCallbacks LoadDelegate(); | ||
|
|
||
| // The FreeSWITCH API interface callback delegate | ||
| private delegate int NativeAPICallback(string command, IntPtr sessionptr, IntPtr streamptr); | ||
| // The FreeSWITCH API interface callback delegate | ||
| private delegate int NativeAPICallback(string command, IntPtr sessionptr, IntPtr streamptr); | ||
|
|
||
| // The FreeSWITCH APP interface callback delegate | ||
| private delegate void NativeAPPCallback(IntPtr sessionptr, string data); | ||
| // The FreeSWITCH APP interface callback delegate | ||
| private delegate void NativeAPPCallback(IntPtr sessionptr, string data); | ||
|
|
||
| // The FreeSWITCH APP interface callback delegate | ||
| private delegate string NativeXMLCallback(string section, string tag, string key, string value, IntPtr eventptr); | ||
| // The FreeSWITCH APP interface callback delegate | ||
| private delegate string NativeXMLCallback(string section, string tag, string key, string value, IntPtr eventptr); | ||
|
|
||
| // Contains all native callbacks that will be called from the native host, each callback | ||
| // is produced by marshalling delegates to native function pointers | ||
| // Important: Must maintain the same structure in native_callbacks_t in mod_coreclr.c | ||
| // Contains all native callbacks that will be called from the native host, each callback | ||
| // is produced by marshalling delegates to native function pointers | ||
| // Important: Must maintain the same structure in native_callbacks_t in mod_coreclr.c | ||
| [StructLayout(LayoutKind.Sequential)] | ||
| private struct NativeCallbacks | ||
| public struct NativeCallbacks | ||
| { | ||
| public IntPtr NativeAPICallback; | ||
| public IntPtr NativeAPPCallback; | ||
| public IntPtr NativeXMLCallback; | ||
| public IntPtr NativeAPICallback; | ||
| public IntPtr NativeAPPCallback; | ||
| public IntPtr NativeXMLCallback; | ||
| } | ||
|
|
||
| // This is the only predefined entry point, this must match what mod_coreclr.c is looking for | ||
| private static NativeCallbacks Load() | ||
| private static NativeAPICallback sNativeAPICallback = null; | ||
| private static NativeAPPCallback sNativeAPPCallback = null; | ||
| private static NativeXMLCallback sNativeXMLCallback = null; | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add: |
||
| // This is the only predefined entry point, this must match what mod_coreclr.c is looking for | ||
| public static NativeCallbacks Load() | ||
| { | ||
| // Register some reserved Managed API's | ||
| //sAPIRegistry.TryAdd("load", LoadAPI); | ||
| //var myLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); | ||
| //PluginsContainer.LoadPluginsFromSubDirs(myLocation); | ||
|
|
||
| sNativeAPICallback = new NativeAPICallback(NativeAPIHandler); | ||
| sNativeAPPCallback = new NativeAPPCallback(NativeAPPHandler); | ||
| sNativeXMLCallback = new NativeXMLCallback(NativeXMLHandler); | ||
| // Return the marshalled callbacks for the native interfaces | ||
| return new NativeCallbacks | ||
| { | ||
| NativeAPICallback = Marshal.GetFunctionPointerForDelegate<NativeAPICallback>(sNativeAPICallback), | ||
| NativeAPPCallback = Marshal.GetFunctionPointerForDelegate<NativeAPPCallback>(sNativeAPPCallback), | ||
| NativeXMLCallback = Marshal.GetFunctionPointerForDelegate<NativeXMLCallback>(sNativeXMLCallback) | ||
| }; | ||
| } | ||
|
|
||
| // The Managed API interface callback delegate | ||
| public delegate string APICallback(string args, ManagedSession session); | ||
| // The Managed API callback registry | ||
| // TODO: value type subject to change to a more complex type including an APIAttribute configuration | ||
| private static ConcurrentDictionary<string, APICallback> sAPIRegistry = new ConcurrentDictionary<string, APICallback>(); | ||
|
|
||
| // This is the FreeSWITCH API interface callback handler which is bound to "coreclr" API commands | ||
| private static int NativeAPIHandler(string command, IntPtr sessionptr, IntPtr streamptr) | ||
| { | ||
| using ManagedSession session = new ManagedSession(new SWIGTYPE_p_switch_core_session_t(sessionptr, false)); | ||
| using Stream stream = new Stream(new SWIGTYPE_p_switch_stream_handle_t(streamptr, false)); | ||
|
|
||
|
|
||
| // for now just call other dispatcher and return Todo: remove the rest of this code | ||
| return PluginsContainer.DispatchAPI(command, stream, session); | ||
|
|
||
| } | ||
|
|
||
| // The Managed APP interface callback delegate | ||
| public delegate void APPCallback(string args, ManagedSession session); | ||
| // The Managed APP callback registry | ||
| // TODO: value type subject to change to a more complex type including an APPAttribute configuration | ||
| private static ConcurrentDictionary<string, APPCallback> sAPPRegistry = new ConcurrentDictionary<string, APPCallback>(); | ||
|
|
||
| // This is the FreeSWITCH APP interface callback handler which is bound to "coreclr" APP commands | ||
| private static void NativeAPPHandler(IntPtr sessionptr, string data) | ||
| { | ||
| // Register some reserved Managed API's | ||
| sAPIRegistry.TryAdd("load", LoadAPI); | ||
|
|
||
| // Return the marshalled callbacks for the native interfaces | ||
| return new NativeCallbacks { | ||
| NativeAPICallback = Marshal.GetFunctionPointerForDelegate<NativeAPICallback>(NativeAPIHandler), | ||
| NativeAPPCallback = Marshal.GetFunctionPointerForDelegate<NativeAPPCallback>(NativeAPPHandler), | ||
| NativeXMLCallback = Marshal.GetFunctionPointerForDelegate<NativeXMLCallback>(NativeXMLHandler) | ||
| }; | ||
| using ManagedSession session = new ManagedSession(new SWIGTYPE_p_switch_core_session_t(sessionptr, false)); | ||
|
|
||
| PluginsContainer.DispatchDialPlanApp(data, session); | ||
| return; | ||
|
|
||
| } | ||
|
|
||
| // The Managed API interface callback delegate | ||
| public delegate string APICallback(string args, ManagedSession session); | ||
| // The Managed API callback registry | ||
| // TODO: value type subject to change to a more complex type including an APIAttribute configuration | ||
| private static ConcurrentDictionary<string, APICallback> sAPIRegistry = new ConcurrentDictionary<string, APICallback>(); | ||
|
|
||
| // This is the FreeSWITCH API interface callback handler which is bound to "coreclr" API commands | ||
| private static int NativeAPIHandler(string command, IntPtr sessionptr, IntPtr streamptr) | ||
| { | ||
| using ManagedSession session = new ManagedSession(new SWIGTYPE_p_switch_core_session_t(sessionptr, false)); | ||
| using Stream stream = new Stream(new SWIGTYPE_p_switch_stream_handle_t(streamptr, false)); | ||
|
|
||
| string args = command; | ||
| if (!ParseArgument(ref args, out command, ' ')) | ||
| { | ||
| Log.WriteLine(LogLevel.Error, "Missing Managed API"); | ||
| stream.Write("-ERROR Missing Managed API"); | ||
| return 0; | ||
| } | ||
| Log.WriteLine(LogLevel.Info, "Managed API: {0} {1}", command, args); | ||
|
|
||
| if (!sAPIRegistry.TryGetValue(command.ToLower(), out APICallback callback)) | ||
| { | ||
| Log.WriteLine(LogLevel.Error, "Managed API does not exist"); | ||
| stream.Write("-ERROR Managed API does not exist"); | ||
| return 0; | ||
| } | ||
| string result = null; | ||
| try | ||
| { | ||
| result = callback(args, session); | ||
| } | ||
| catch (Exception) | ||
| { | ||
| // TODO: Log more of the exception data out | ||
| Log.WriteLine(LogLevel.Error, "Managed API exception"); | ||
| result = "-ERROR Managed API exception"; | ||
| } | ||
| if (result != null) stream.Write(result); | ||
| return 0; | ||
| } | ||
|
|
||
| // The Managed APP interface callback delegate | ||
| public delegate void APPCallback(string args, ManagedSession session); | ||
| // The Managed APP callback registry | ||
| // TODO: value type subject to change to a more complex type including an APPAttribute configuration | ||
| private static ConcurrentDictionary<string, APPCallback> sAPPRegistry = new ConcurrentDictionary<string, APPCallback>(); | ||
|
|
||
| // This is the FreeSWITCH APP interface callback handler which is bound to "coreclr" APP commands | ||
| private static void NativeAPPHandler(IntPtr sessionptr, string data) | ||
| { | ||
| using ManagedSession session = new ManagedSession(new SWIGTYPE_p_switch_core_session_t(sessionptr, false)); | ||
|
|
||
| string args = data; | ||
| if (!ParseArgument(ref args, out string command, ' ')) | ||
| { | ||
| Log.WriteLine(LogLevel.Error, "Missing Managed APP"); | ||
| return; | ||
| } | ||
| Log.WriteLine(LogLevel.Info, "Managed APP: {0} {1}", command, args); | ||
|
|
||
| if (!sAPPRegistry.TryGetValue(command.ToLower(), out APPCallback callback)) | ||
| { | ||
| Log.WriteLine(LogLevel.Error, "Managed APP does not exist"); | ||
| return; | ||
| } | ||
| try | ||
| { | ||
| callback(args, session); | ||
| } | ||
| catch (Exception) | ||
| { | ||
| // TODO: Log more of the exception data out | ||
| Log.WriteLine(LogLevel.Error, "Managed APP exception"); | ||
| } | ||
| } | ||
|
|
||
| // The Managed XML interface callback delegate | ||
| public delegate void XMLCallback(string section, string tag, string key, string value, Event evt, ref string result); | ||
|
|
||
| public static event XMLCallback OnXMLSearch; | ||
|
|
||
| // This is the FreeSWITCH XML interface callback handler | ||
| private static string NativeXMLHandler(string section, string tag, string key, string value, IntPtr eventptr) | ||
| { | ||
| using Event evt = new Event(new SWIGTYPE_p_switch_event_t(eventptr, false), 0); | ||
| Log.WriteLine(LogLevel.Info, "Managed XML Handler: {0} - {1} - {2} - {3}", section, tag, key, value); | ||
| string result = null; | ||
| OnXMLSearch?.Invoke(section, tag, key, value, evt, ref result); | ||
| return result; | ||
| } | ||
|
|
||
| // TODO: Put this somewhere more reusable | ||
| private static bool ParseArgument(ref string args, out string arg, char separator) | ||
| { | ||
| args = args.Trim(); | ||
| int eoa = args.IndexOf(separator); | ||
| arg = null; | ||
| if (eoa < 0) | ||
| { | ||
| string tmp = args; | ||
| args = string.Empty; | ||
| if (tmp.Length > 0) arg = tmp; | ||
| return arg != null; | ||
| } | ||
| arg = args.Substring(0, eoa); | ||
| args = args.Remove(0, eoa + 1).Trim(); | ||
| return true; | ||
| } | ||
|
|
||
| // Managed API for loading user assemblies and reflecting on attributes to register callbacks | ||
| private static string LoadAPI(string args, ManagedSession session) | ||
| { | ||
| string path = Path.GetFullPath(args); | ||
| if (!Path.HasExtension(path)) path = Path.ChangeExtension(path, ".dll"); | ||
| if (!File.Exists(path)) | ||
| { | ||
| Log.WriteLine(LogLevel.Error, "File not found: {0}", path); | ||
| return "-ERROR File not found"; | ||
| } | ||
|
|
||
| // TODO: Load the assembly, kick off reflection scan for relevant attributes, add API's to sAPIRegistry | ||
|
|
||
| return "+OK " + path; | ||
| } | ||
| // The Managed XML interface callback delegate | ||
| public delegate void XMLCallback(string section, string tag, string key, string value, Event evt, ref string result); | ||
|
|
||
| // public static event XMLCallback OnXMLSearch; | ||
|
|
||
| // This is the FreeSWITCH XML interface callback handler | ||
| private static string NativeXMLHandler(string section, string tag, string key, string value, IntPtr eventptr) | ||
| { | ||
| using Event evt = new Event(new SWIGTYPE_p_switch_event_t(eventptr, false), 0); | ||
| //Log.WriteLine(LogLevel.Info, "Managed XML Handler: {0} - {1} - {2} - {3}", section, tag, key, value); | ||
| return PluginsContainer.DispatchXMLCallback(section, tag, key, value, evt); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,9 +9,19 @@ | |
| <AllOutputs Include="$(OutputPath)$(MSBuildProjectName).dll" /> | ||
| <AllOutputs Include="$(OutputPath)$(MSBuildProjectName).runtimeconfig.json" /> | ||
| <AllOutputs Include="$(OutputPath)$(MSBuildProjectName).deps.json" /> | ||
| <AllOutputs Include="$(OutputPath)PluginInterface.dll" /> | ||
| </ItemGroup> | ||
|
|
||
| <Copy SourceFiles="@(AllOutputs)" DestinationFolder="$(MSBuildProjectDirectory)/../LoaderRuntime" /> | ||
| </Target> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\PluginInterface\PluginInterface.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <FrameworkReference Include="Microsoft.AspNetCore.App" /> | ||
| </ItemGroup> | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the ASP reference necessary or left over from testing? |
||
|
|
||
| </Project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
| <PropertyGroup> | ||
| <ShowAllFiles>true</ShowAllFiles> | ||
| </PropertyGroup> | ||
| </Project> | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this file, .user files should be local only. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Reflection; | ||
| using System.Runtime.Loader; | ||
| using System.Text; | ||
|
|
||
| namespace FreeSWITCH | ||
| { | ||
| public class PluginLoadContext : AssemblyLoadContext | ||
| { | ||
| private AssemblyDependencyResolver _resolver; | ||
|
|
||
| public List<PluginInterface.IPluginDispatcher> Dispatchers { get; set; } = new List<PluginInterface.IPluginDispatcher>(); | ||
|
|
||
| public PluginLoadContext(string pluginPath) | ||
| { | ||
| _resolver = new AssemblyDependencyResolver(pluginPath); | ||
| } | ||
|
|
||
| protected override Assembly Load(AssemblyName assemblyName) | ||
| { | ||
| var assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); | ||
|
|
||
| return (assemblyPath != null ? LoadFromAssemblyPath(assemblyPath) | ||
| : AssemblyLoadContext.GetLoadContext(typeof(PluginLoadContext).Assembly).LoadFromAssemblyName(assemblyName)); | ||
| } | ||
|
|
||
| protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) | ||
| { | ||
| string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName); | ||
| if (libraryPath != null) | ||
| { | ||
| return LoadUnmanagedDllFromPath(libraryPath); | ||
| } | ||
|
|
||
| return IntPtr.Zero; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reduce all this to just:
.vs