Merge pull request #93 in FS/freeswitch from ~RAVENOX/freeswitch:mod_managed_improvements to master

* commit '889b678e58bf38eb86df7885b8f054d3d9d92d74':
  mod_managed: Added GetPtr to Util class for internal pointers extraction (very useful when using native api)
  mod_managed: Added pure CreateStateHandlerDelegate in ManagedSession for native api usage
  mod_managed: added console log level
  mod_managed: support per-module references directory
  mod_managed: not crash when cannot remove shadow directory (this sometimes happens when restarting from FS console)
  mod_managed: managedlist command must return value to api stream instead of log
This commit is contained in:
Mike Jerris 2014-11-04 16:35:11 -06:00
commit 2b4082c236
5 changed files with 121 additions and 25 deletions

View File

@ -26,6 +26,7 @@
* Michael Giagnocavo <mgg@giagnocavo.net>
* David Brazier <David.Brazier@360crm.co.uk>
* Jeff Lenk <jeff@jefflenk.com>
* Artur Kraev <ravenox@gmail.com>
*
* Loader.cs -- mod_managed loader
*
@ -33,7 +34,6 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Linq;
using System.Reflection;
@ -46,16 +46,15 @@ namespace FreeSWITCH {
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ExecuteDelegate(string cmd, IntPtr streamH, IntPtr eventH);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ExecuteBackgroundDelegate(string cmd);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool RunDelegate(string cmd, IntPtr session);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ReloadDelegate(string cmd);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ListDelegate(string cmd);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate bool ReloadDelegate(string cmd);
static readonly ExecuteDelegate _execute = Execute;
static readonly ExecuteBackgroundDelegate _executeBackground = ExecuteBackground;
static readonly RunDelegate _run = Run;
static readonly ReloadDelegate _reload = Reload;
static readonly ListDelegate _list = List;
static readonly ExecuteDelegate _list = List;
[DllImport("mod_managed", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
static extern void InitManagedDelegates(RunDelegate run, ExecuteDelegate execute, ExecuteBackgroundDelegate executeBackground, ReloadDelegate reload, ListDelegate list);
static extern void InitManagedDelegates(RunDelegate run, ExecuteDelegate execute, ExecuteBackgroundDelegate executeBackground, ReloadDelegate reload, ExecuteDelegate list);
static readonly object loaderLock = new object();
@ -65,13 +64,23 @@ namespace FreeSWITCH {
public static bool Load() {
managedDir = Path.Combine(Native.freeswitch.SWITCH_GLOBAL_dirs.mod_dir, "managed");
shadowDir = Path.Combine(managedDir, "shadow");
if (Directory.Exists(shadowDir)) {
Directory.Delete(shadowDir, true);
if (Directory.Exists(shadowDir))
{
try
{
Directory.Delete(shadowDir, true);
}
catch (Exception ex)
{
Log.WriteLine(LogLevel.Warning, "Cannot delete shadow directory: {0}", ex);
}
Directory.CreateDirectory(shadowDir);
}
Log.WriteLine(LogLevel.Debug, "FreeSWITCH.Managed loader is starting with directory '{0}'.", managedDir);
if (!Directory.Exists(managedDir)) {
if (!Directory.Exists(managedDir))
{
Log.WriteLine(LogLevel.Error, "Managed directory not found: {0}", managedDir);
return false;
}
@ -220,11 +229,38 @@ namespace FreeSWITCH {
setup.ConfigurationFile = fileName + ".config";
}
setup.ApplicationBase = Native.freeswitch.SWITCH_GLOBAL_dirs.mod_dir;
setup.ShadowCopyDirectories = managedDir + ";";
setup.LoaderOptimization = LoaderOptimization.MultiDomainHost; // TODO: would MultiDomain work better since FreeSWITCH.Managed isn't gac'd?
setup.CachePath = shadowDir;
setup.ShadowCopyFiles = "true";
setup.PrivateBinPath = "managed";
// computing private bin path
var binPath = setup.PrivateBinPath ?? string.Empty;
var binPaths = binPath.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim())
.ToList();
// adding "managed" (modules) directory
if (!binPaths.Contains("managed", StringComparer.OrdinalIgnoreCase))
{
binPaths.Add("managed");
}
// adding "managed/<modulename>" directory for per-module references support
var moduleRefsDir = Path.GetFileName(fileName);
moduleRefsDir = Path.GetFileNameWithoutExtension(moduleRefsDir);
if (moduleRefsDir != null && moduleRefsDir.Trim() != "")
{
moduleRefsDir = Path.Combine("managed", moduleRefsDir);
if (!binPaths.Contains(moduleRefsDir, StringComparer.OrdinalIgnoreCase))
{
binPaths.Add(moduleRefsDir);
}
}
// bringing all together
setup.PrivateBinPath = string.Join(";", binPaths);
// Create domain and load PM inside
System.Threading.Interlocked.Increment(ref appDomainCount);
@ -408,18 +444,33 @@ namespace FreeSWITCH {
}
}
public static bool List(string command) {
try {
Log.WriteLine(LogLevel.Info, "Available APIs:");
getApiExecs().Values.ForEach(x => {
Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray()));
});
Log.WriteLine(LogLevel.Info, "Available Apps:");
getAppExecs().Values.ForEach(x => {
Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray()));
});
public static bool List(string command, IntPtr streamHandle, IntPtr eventHandle)
{
try
{
if (streamHandle != IntPtr.Zero)
{
using (var stream = new Native.Stream(new Native.switch_stream_handle(streamHandle, false)))
{
stream.Write("Available APIs:\n");
getApiExecs().Values.ForEach(x => stream.Write(string.Format("{0}: {1}\n", x.Name, String.Join(",", x.Aliases.ToArray()))));
stream.Write("Available Apps:\n");
getAppExecs().Values.ForEach(x => stream.Write(string.Format("{0}: {1}\n", x.Name, String.Join(",", x.Aliases.ToArray()))));
}
}
else
{
Log.WriteLine(LogLevel.Info, "Available APIs:");
getApiExecs().Values.ForEach(x => Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray())));
Log.WriteLine(LogLevel.Info, "Available Apps:");
getAppExecs().Values.ForEach(x => Log.WriteLine(LogLevel.Info, "{0}: {1}", x.Name, String.Join(",", x.Aliases.ToArray())));
}
return true;
} catch (Exception ex) {
}
catch (Exception ex)
{
Log.WriteLine(LogLevel.Error, "Exception listing managed modules: {0}", ex.ToString());
return false;
}

View File

@ -57,6 +57,7 @@ namespace FreeSWITCH
static string ToLogString(this LogLevel level)
{
switch (level) {
case LogLevel.Console: return "CONSOLE";
case LogLevel.Alert: return "ALERT";
case LogLevel.Critical: return "CRIT";
case LogLevel.Debug: return "DEBUG";
@ -85,6 +86,7 @@ namespace FreeSWITCH
};*/
public enum LogLevel
{
Console,
Debug,
Info,
Error,

View File

@ -149,6 +149,23 @@ namespace FreeSWITCH.Native
};
return del;
}
/// <summary>Wraps a nice handler into a delegate suitable for reverse P/Invoke. For native api using</summary>
public static switch_state_handler_t_delegate CreateStateHandlerDelegate(Action<ManagedSession> handler)
{
// We create a ManagedSession on top of the session so callbacks can use it "nicely"
// Then we sort of dispose it.
switch_state_handler_t_delegate del = ptr =>
{
using (var sess = new ManagedSession(new SWIGTYPE_p_switch_core_session(ptr, false)))
{
handler(sess);
return switch_status_t.SWITCH_STATUS_SUCCESS;
}
};
return del;
}
public static SWIGTYPE_p_f_p_switch_core_session__switch_status_t WrapStateHandlerDelegate(switch_state_handler_t_delegate del) {
return new SWIGTYPE_p_f_p_switch_core_session__switch_status_t(Marshal.GetFunctionPointerForDelegate(del), false);
}

View File

@ -46,5 +46,31 @@ namespace FreeSWITCH {
if (cons == null) throw new ArgumentException(ty.Name + " constructor not found.");
return (T)cons.Invoke(new object[] { cPtr, false });
}
/// <summary>
/// Getting IntPtr from wrapper
/// </summary>
/// <typeparam name="T">swig generated class</typeparam>
/// <param name="obj">instance</param>
/// <returns>Original pointer</returns>
public static IntPtr GetPtr<T>(T obj)
{
// internal static HandleRef getCPtr(CoreSession obj)
var ty = typeof(T);
var bflags = BindingFlags.Static | BindingFlags.NonPublic;
var getCPtr = ty.GetMethod("getCPtr", bflags, null, new[] { typeof(T) }, null);
if (getCPtr != null)
{
var handleRef = getCPtr.Invoke(null, new object[] { obj });
if (handleRef is HandleRef)
{
return ((HandleRef)handleRef).Handle;
}
}
return IntPtr.Zero;
}
}
}

View File

@ -26,6 +26,7 @@
* Michael Giagnocavo <mgg@giagnocavo.net>
* David Brazier <David.Brazier@360crm.co.uk>
* Jeff Lenk <jlenk@frontiernet.net>
* Artur Kraev <ravenox@gmail.com>
*
* mod_mono.cpp -- FreeSWITCH mod_mono main class
*
@ -73,14 +74,13 @@ typedef int (*runFunction)(const char *data, void *sessionPtr);
typedef int (*executeFunction)(const char *cmd, void *stream, void *Event);
typedef int (*executeBackgroundFunction)(const char* cmd);
typedef int (*reloadFunction)(const char* cmd);
typedef int (*listFunction)(const char* cmd);
static runFunction runDelegate;
static executeFunction executeDelegate;
static executeBackgroundFunction executeBackgroundDelegate;
static reloadFunction reloadDelegate;
static listFunction listDelegate;
static executeFunction listDelegate;
SWITCH_MOD_DECLARE_NONSTD(void) InitManagedDelegates(runFunction run, executeFunction execute, executeBackgroundFunction executeBackground, reloadFunction reload, listFunction list)
SWITCH_MOD_DECLARE_NONSTD(void) InitManagedDelegates(runFunction run, executeFunction execute, executeBackgroundFunction executeBackground, reloadFunction reload, executeFunction list)
{
runDelegate = run;
executeDelegate = execute;
@ -451,7 +451,7 @@ SWITCH_STANDARD_API(managedlist_api_function)
#ifndef _MANAGED
mono_thread_attach(globals.domain);
#endif
listDelegate(cmd);
listDelegate(cmd, stream, stream->param_event);
#ifndef _MANAGED
mono_thread_detach(mono_thread_current());
#endif