diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/App.config b/src/mod/languages/mod_managed/managed/examples/easyroute/App.config new file mode 100644 index 0000000000..214f616f9e --- /dev/null +++ b/src/mod/languages/mod_managed/managed/examples/easyroute/App.config @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<configuration> + <appSettings> + <add key="connectionString" value="DSN=easyroute;User=root;Password=;" /> + <add key="defaultProfile" value="sofia/default"/> + <add key="defaultGateway" value="192.168.1.1"/> + <!-- customQuery can be defined. Fields must be in the same order, and the number parameter must be %number% --> + <!-- <add key="customQuery" value="SELECT gateways.gateway_ip, gateways.group, gateways.limit, gateways.techprofile, numbers.acctcode, numbers.translated from gateways, numbers where numbers.number = %number% and numbers.gateway_id = gateways.gateway_id;" /> --> + </appSettings> +</configuration> \ No newline at end of file diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.fsproj b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.fsproj new file mode 100644 index 0000000000..3008e6f083 --- /dev/null +++ b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.fsproj @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{7b5259d4-eaa0-4bcc-9eac-8dc054a4a092}</ProjectGuid> + <OutputType>Library</OutputType> + <RootNamespace>fs_easyroute</RootNamespace> + <AssemblyName>easyroute</AssemblyName> + <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> + <Name>EasyRoute</Name> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <Tailcalls>false</Tailcalls> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <WarningLevel>3</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <Tailcalls>true</Tailcalls> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <WarningLevel>3</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> + <Tailcalls>false</Tailcalls> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> + <OtherFlags> + </OtherFlags> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Compile Include="easyroute.fs" /> + <Content Include="App.config" /> + </ItemGroup> + <ItemGroup> + <Reference Include="FreeSWITCH.Managed, Version=1.0.4.0, Culture=neutral, PublicKeyToken=null"> + <Name>FreeSWITCH.Managed</Name> + <AssemblyName>FreeSWITCH.Managed.dll</AssemblyName> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\FreeSWITCH.Managed.dll</HintPath> + <Private>True</Private> + </Reference> + <Reference Include="FSharp.PowerPack, Version=1.9.6.16, Culture=neutral, PublicKeyToken=a19089b1c74d0809"> + <Name>FSharp.PowerPack</Name> + <AssemblyName>FSharp.PowerPack.dll</AssemblyName> + <SpecificVersion>False</SpecificVersion> + </Reference> + <Reference Include="mscorlib" /> + <Reference Include="FSharp.Core" /> + <Reference Include="System" /> + <Reference Include="System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> + <Name>System.Configuration</Name> + <AssemblyName>System.configuration.dll</AssemblyName> + <SpecificVersion>False</SpecificVersion> + </Reference> + <Reference Include="System.Core"> + <RequiredTargetFramework>3.5</RequiredTargetFramework> + </Reference> + <Reference Include="System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <Name>System.Data</Name> + <AssemblyName>System.Data.dll</AssemblyName> + <SpecificVersion>False</SpecificVersion> + </Reference> + <Reference Include="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <Name>System.Transactions</Name> + <AssemblyName>System.Transactions.dll</AssemblyName> + <SpecificVersion>False</SpecificVersion> + </Reference> + </ItemGroup> + <Import Project="$(MSBuildExtensionsPath)\FSharp\1.0\Microsoft.FSharp.Targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project> \ No newline at end of file diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.sln b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.sln new file mode 100644 index 0000000000..3d2b6acdae --- /dev/null +++ b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "EasyRoute", "EasyRoute.fsproj", "{7B5259D4-EAA0-4BCC-9EAC-8DC054A4A092}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7B5259D4-EAA0-4BCC-9EAC-8DC054A4A092}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B5259D4-EAA0-4BCC-9EAC-8DC054A4A092}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B5259D4-EAA0-4BCC-9EAC-8DC054A4A092}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B5259D4-EAA0-4BCC-9EAC-8DC054A4A092}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.suo b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.suo new file mode 100644 index 0000000000..354e68d201 Binary files /dev/null and b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.suo differ diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll new file mode 100644 index 0000000000..3665f8c6bb Binary files /dev/null and b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll differ diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll.config b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll.config new file mode 100644 index 0000000000..214f616f9e --- /dev/null +++ b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll.config @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<configuration> + <appSettings> + <add key="connectionString" value="DSN=easyroute;User=root;Password=;" /> + <add key="defaultProfile" value="sofia/default"/> + <add key="defaultGateway" value="192.168.1.1"/> + <!-- customQuery can be defined. Fields must be in the same order, and the number parameter must be %number% --> + <!-- <add key="customQuery" value="SELECT gateways.gateway_ip, gateways.group, gateways.limit, gateways.techprofile, numbers.acctcode, numbers.translated from gateways, numbers where numbers.number = %number% and numbers.gateway_id = gateways.gateway_id;" /> --> + </appSettings> +</configuration> \ No newline at end of file diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.fs b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.fs new file mode 100644 index 0000000000..d3806b4711 --- /dev/null +++ b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.fs @@ -0,0 +1,91 @@ +// To get unixodbc to work on Mono Linux, you may need to create an odbc32.dll link: ln -s /lib64/libodbc.so /lib64/odbc32.dll +open System +open System.Data +open FreeSWITCH + +type QueryResult = { dialstring: string; group: string; acctcode: string; limit: int; translated: string } + +module easyroute = + let getAppSetting (name:string) = match Configuration.ConfigurationManager.AppSettings.Get name with null -> "" | x -> x + let connString = getAppSetting "connectionString" + let defaultProfile = getAppSetting "defaultProfile" + let defaultGateway = getAppSetting "defaultGateway" + let query = match getAppSetting "customQuery" with + | "" -> "SELECT gateways.gateway_ip, gateways.group, gateways.limit, gateways.techprofile, numbers.acctcode, numbers.translated from gateways, numbers where numbers.number = %number% and numbers.gateway_id = gateways.gateway_id;" + | x -> x + let configOk = [ connString; defaultProfile; defaultGateway; query; ] |> List.forall (String.IsNullOrEmpty >> not) + + let formatDialstring number gateway profile separator = + match separator with + | None -> sprintf "%s/%s%s" profile number gateway + | Some s -> sprintf "%s/%s%s%s" profile number s gateway + + let getDefaultResult number sep = { + dialstring = formatDialstring number defaultGateway defaultProfile sep; + limit = 9999; group = ""; acctcode = ""; translated = number; } + + let readResult (r: IDataReader) number sep = + let defString def = function null | "" -> def | s -> s + let gw = defString defaultGateway <| r.GetString(0) + let group = r.GetString(1) + let limit = match r.GetInt32(2) with 0 -> 9999 | x -> x + let profile = defString defaultProfile <| r.GetString(3) + let acctcode = r.GetString(4) + let translated = r.GetString(5) + let dialstring = formatDialstring number gw profile sep + { dialstring = dialstring; limit = limit; group = group; acctcode = acctcode; translated = translated; } + + let lookup (number: string) sep = + try + let query = query.Replace("%number%", sprintf "'%s'" (number.Replace(@"\'", "'").Replace("'", "''"))) // Don't use params cause some odbc drivers are awesome + Log.WriteLine(LogLevel.Debug, "EasyRoute query prepared: {0}", query) + use conn = new Odbc.OdbcConnection(connString) + use comm = new Odbc.OdbcCommand(query, conn) + conn.Open() + use reader = comm.ExecuteReader CommandBehavior.SingleRow + match reader.Read() with + | true -> readResult reader number sep + | false -> Log.WriteLine(LogLevel.Error, "No records for {0}; setting default route.", number) + getDefaultResult number sep + with ex -> Log.WriteLine(LogLevel.Error, "Exception getting route for {0}. Setting default route. Exception: {1}", number, ex.ToString()) + getDefaultResult number sep + + // Returns tuple: number * separator option * field option + let parseArgs args = + let args = String.split [' '] args + let num = List.hd args + let opt = Map.of_list (List.tl args |> List.map (fun x -> match x.Split([|'='|], 2) with + | [|n;v|] -> n, Some v + | arr -> arr.[0], None)) + (num, defaultArg (opt.TryFind "separator") (Some "@"), defaultArg (opt.TryFind "field") (None)) +open easyroute + +type EasyRoute() = + interface ILoadNotificationPlugin with + member x.Load() = + if not configOk then Log.WriteLine(LogLevel.Alert, "EasyRoute configuration is missing values.") + configOk + + interface IApiPlugin with + member x.ExecuteBackground ctx = + Log.WriteLine(LogLevel.Error, "Background execution not supported for EasyRoute.") + member x.Execute ctx = + let num, sep, field = parseArgs ctx.Arguments + let res = lookup num sep + let sw = ctx.Stream.Write + match field with + | None -> sw "Number \tLimit \tGroup \tAcctCode \tDialstring\n" + sw (sprintf "%-10s\t%-10d\t%-10s\t%-10s\t%s\n" res.translated res.limit res.group res.acctcode res.dialstring) + | Some "dialstring" -> sw res.dialstring + | Some "translated" -> sw res.translated + | Some "limit" -> sw (string res.limit) + | Some "group" -> sw res.group + | Some "acctcode" -> sw res.acctcode + | _ -> sw "Invalid input!\n" + + interface IAppPlugin with + member x.Run ctx = + let num, sep, field = parseArgs ctx.Arguments + let res = lookup num sep + [ "easy_destnum", res.translated; "easy_dialstring", res.dialstring; "easy_group", res.group; "easy_limit", string res.limit; "easy_acctcode", res.acctcode] + |> List.iter ctx.Session.SetVariable diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.pdb b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.pdb new file mode 100644 index 0000000000..010b2d60fd Binary files /dev/null and b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.pdb differ