mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-12 22:34:18 +00:00
Oops. Here's the actual new mod_managed files
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@14366 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
1 parent
eb873d8898
commit
e9a46e8942
3 files changed
+624
No files matched your search
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - mod_managed
|
||||
* Copyright (C) 2008, Michael Giagnocavo <mgg@giagnocavo.net>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - mod_managed
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Giagnocavo <mgg@giagnocavo.net>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Michael Giagnocavo <mgg@giagnocavo.net>
|
||||
*
|
||||
* ScriptPluginManager.cs -- Dynamic compilation and script execution
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.CodeDom;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
|
||||
namespace FreeSWITCH {
|
||||
|
||||
public enum ScriptContextType {
|
||||
App,
|
||||
Api,
|
||||
ApiBackground,
|
||||
}
|
||||
|
||||
public static class Script {
|
||||
|
||||
[ThreadStatic]
|
||||
internal static ScriptContextType contextType;
|
||||
[ThreadStatic]
|
||||
internal static object context;
|
||||
|
||||
public static ScriptContextType ContextType { get { return contextType; } }
|
||||
|
||||
public static ApiContext GetApiContext() {
|
||||
return getContext<ApiContext>(ScriptContextType.Api);
|
||||
}
|
||||
public static ApiBackgroundContext GetApiBackgroundContext() {
|
||||
return getContext<ApiBackgroundContext>(ScriptContextType.ApiBackground);
|
||||
}
|
||||
public static AppContext GetAppContext() {
|
||||
return getContext<AppContext>(ScriptContextType.App);
|
||||
}
|
||||
|
||||
public static T getContext<T>(ScriptContextType sct) {
|
||||
var ctx = context;
|
||||
if (ctx == null) throw new InvalidOperationException("Current context is null.");
|
||||
if (contextType != sct) throw new InvalidOperationException("Current ScriptContextType is not " + sct.ToString() + ".");
|
||||
return (T)ctx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class ScriptPluginManager : PluginManager {
|
||||
|
||||
protected override bool LoadInternal(string fileName) {
|
||||
Assembly asm;
|
||||
if (Path.GetExtension(fileName).ToLowerInvariant() == ".exe") {
|
||||
asm = Assembly.LoadFrom(fileName);
|
||||
} else {
|
||||
asm = compileAssembly(fileName);
|
||||
}
|
||||
if (asm == null) return false;
|
||||
|
||||
return processAssembly(fileName, asm);
|
||||
}
|
||||
|
||||
Assembly compileAssembly(string fileName) {
|
||||
var comp = new CompilerParameters();
|
||||
var mainRefs = new List<string> {
|
||||
Path.Combine(Native.freeswitch.SWITCH_GLOBAL_dirs.mod_dir, "FreeSWITCH.Managed.dll"),
|
||||
"System.dll", "System.Xml.dll", "System.Data.dll"
|
||||
};
|
||||
var extraRefs = new List<string> {
|
||||
"System.Core.dll",
|
||||
"System.Xml.Linq.dll",
|
||||
};
|
||||
comp.ReferencedAssemblies.AddRange(mainRefs.ToArray());
|
||||
comp.ReferencedAssemblies.AddRange(extraRefs.ToArray());
|
||||
CodeDomProvider cdp;
|
||||
var ext = Path.GetExtension(fileName).ToLowerInvariant();
|
||||
switch (ext) {
|
||||
case ".fsx":
|
||||
cdp = CodeDomProvider.CreateProvider("f#");
|
||||
break;
|
||||
case ".csx":
|
||||
cdp = new Microsoft.CSharp.CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v3.5" } });
|
||||
break;
|
||||
case ".vbx":
|
||||
cdp = new Microsoft.VisualBasic.VBCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v3.5" } });
|
||||
break;
|
||||
case ".jsx":
|
||||
// Have to figure out better JS support
|
||||
cdp = CodeDomProvider.CreateProvider("js");
|
||||
extraRefs.ForEach(comp.ReferencedAssemblies.Remove);
|
||||
break;
|
||||
default:
|
||||
if (CodeDomProvider.IsDefinedExtension(ext)) {
|
||||
cdp = CodeDomProvider.CreateProvider(CodeDomProvider.GetLanguageFromExtension(ext));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
comp.GenerateInMemory = true;
|
||||
comp.GenerateExecutable = true;
|
||||
|
||||
Log.WriteLine(LogLevel.Info, "Compiling {0}", fileName);
|
||||
var res = cdp.CompileAssemblyFromFile(comp, fileName);
|
||||
|
||||
var errors = res.Errors.Cast<CompilerError>().Where(x => !x.IsWarning).ToList();
|
||||
if (errors.Count > 0) {
|
||||
Log.WriteLine(LogLevel.Error, "There were {0} errors compiling {1}.", errors.Count, fileName);
|
||||
foreach (var err in errors) {
|
||||
if (string.IsNullOrEmpty(err.FileName)) {
|
||||
Log.WriteLine(LogLevel.Error, "{0}: {1}", err.ErrorNumber, err.ErrorText);
|
||||
} else {
|
||||
Log.WriteLine(LogLevel.Error, "{0}: {1}:{2}:{3} {4}", err.ErrorNumber, err.FileName, err.Line, err.Column, err.ErrorText);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Log.WriteLine(LogLevel.Info, "File {0} compiled successfully.", fileName);
|
||||
return res.CompiledAssembly;
|
||||
}
|
||||
|
||||
bool processAssembly(string fileName, Assembly asm) {
|
||||
var allTypes = asm.GetExportedTypes();
|
||||
if (!RunLoadNotify(allTypes)) return false;
|
||||
|
||||
// Scripts can specify classes too
|
||||
AddApiPlugins(allTypes);
|
||||
AddAppPlugins(allTypes);
|
||||
|
||||
// Add the script executors
|
||||
var entryPoint = getEntryDelegate(asm.EntryPoint);
|
||||
var name = Path.GetFileName(fileName);
|
||||
var aliases = new List<string> { name };
|
||||
this.ApiExecutors.Add(new ApiPluginExecutor(name, aliases, () => new ScriptApiWrapper(entryPoint)));
|
||||
this.AppExecutors.Add(new AppPluginExecutor(name, aliases, () => new ScriptAppWrapper(entryPoint)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class ScriptApiWrapper : IApiPlugin {
|
||||
|
||||
readonly Action entryPoint;
|
||||
public ScriptApiWrapper(Action entryPoint) {
|
||||
this.entryPoint = entryPoint;
|
||||
}
|
||||
|
||||
public void Execute(ApiContext context) {
|
||||
Script.contextType = ScriptContextType.Api;
|
||||
Script.context = context;
|
||||
try {
|
||||
entryPoint();
|
||||
} finally {
|
||||
Script.context = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteBackground(ApiBackgroundContext context) {
|
||||
Script.contextType = ScriptContextType.ApiBackground;
|
||||
Script.context = context;
|
||||
try {
|
||||
entryPoint();
|
||||
} finally {
|
||||
Script.context = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ScriptAppWrapper : IAppPlugin {
|
||||
|
||||
readonly Action entryPoint;
|
||||
public ScriptAppWrapper(Action entryPoint) {
|
||||
this.entryPoint = entryPoint;
|
||||
}
|
||||
|
||||
public void Run(AppContext context) {
|
||||
Script.contextType = ScriptContextType.App;
|
||||
Script.context = context;
|
||||
try {
|
||||
entryPoint();
|
||||
} finally {
|
||||
Script.context = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static Action getEntryDelegate(MethodInfo entryPoint) {
|
||||
if (!entryPoint.IsPublic || !entryPoint.DeclaringType.IsPublic) {
|
||||
Log.WriteLine(LogLevel.Error, "Entry point: {0}.{1} is not public. This may cause errors with Mono.",
|
||||
entryPoint.DeclaringType.FullName, entryPoint.Name);
|
||||
}
|
||||
var dm = new DynamicMethod(entryPoint.DeclaringType.Assembly.GetName().Name + "_entrypoint_" + entryPoint.DeclaringType.FullName + entryPoint.Name, null, null, true);
|
||||
var il = dm.GetILGenerator();
|
||||
var args = entryPoint.GetParameters();
|
||||
if (args.Length > 1) throw new ArgumentException("Cannot handle entry points with more than 1 parameter.");
|
||||
if (args.Length == 1) {
|
||||
if (args[0].ParameterType != typeof(string[])) throw new ArgumentException("Entry point paramter must be a string array.");
|
||||
il.Emit(OpCodes.Ldc_I4_0);
|
||||
il.Emit(OpCodes.Newarr, typeof(string));
|
||||
}
|
||||
il.EmitCall(OpCodes.Call, entryPoint, null);
|
||||
if (entryPoint.ReturnType != typeof(void)) {
|
||||
il.Emit(OpCodes.Pop);
|
||||
}
|
||||
il.Emit(OpCodes.Ret);
|
||||
return (Action)dm.CreateDelegate(typeof(Action));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user