mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-07-27 18:47:55 +00:00
Changed sign key in library MtApiService: using MtApiKey.snk. Added logging into MtApiService and used ILMerge.Task to merge assemblies into one dll.
This commit is contained in:
Executable
+67
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<!-- -->
|
||||
<!-- ILMerge project-specific settings. Almost never need to be set explicitly. -->
|
||||
<!-- for details, see http://research.microsoft.com/en-us/people/mbarnett/ilmerge.aspx -->
|
||||
<!-- -->
|
||||
<!-- *** set this file to Type=None, CopyToOutput=Never *** -->
|
||||
|
||||
<!-- If True, all copy local dependencies will also be merged from referenced projects whether they are referenced in the current project explicitly or not -->
|
||||
<ILMergeTransitive>true</ILMergeTransitive>
|
||||
|
||||
<!-- Extra ILMerge library paths (semicolon-separated). Dont put your package dependencies here, they will be added automagically -->
|
||||
<ILMergeLibraryPath></ILMergeLibraryPath>
|
||||
|
||||
<!-- The solution NuGet package directory if not standard 'SOLUTION\packages' -->
|
||||
<ILMergePackagesPath></ILMergePackagesPath>
|
||||
|
||||
<!-- The merge order file name if differs from standard 'ILMergeOrder.txt' -->
|
||||
<ILMergeOrderFile></ILMergeOrderFile>
|
||||
|
||||
<!-- The strong key file name if not specified in the project -->
|
||||
<ILMergeKeyFile>MtApiKey.snk</ILMergeKeyFile>
|
||||
|
||||
<!-- The assembly version if differs for the version of the main assembly -->
|
||||
<ILMergeAssemblyVersion></ILMergeAssemblyVersion>
|
||||
|
||||
<!-- added in Version 1.0.4 -->
|
||||
<ILMergeFileAlignment></ILMergeFileAlignment>
|
||||
|
||||
<!-- added in Version 1.0.4, default=none -->
|
||||
<ILMergeAllowDuplicateType></ILMergeAllowDuplicateType>
|
||||
|
||||
<!-- If the <see cref="CopyAttributes"/> is also set, any assembly-level attributes names that have the same type are copied over into the target assembly -->
|
||||
<ILMergeAllowMultipleAssemblyLevelAttributes></ILMergeAllowMultipleAssemblyLevelAttributes>
|
||||
|
||||
<!-- See ILMerge documentation -->
|
||||
<ILMergeAllowZeroPeKind></ILMergeAllowZeroPeKind>
|
||||
|
||||
<!-- The assembly level attributes of each input assembly are copied over into the target assembly -->
|
||||
<ILMergeCopyAttributes></ILMergeCopyAttributes>
|
||||
|
||||
<!-- Creates a .pdb file for the output assembly and merges into it any .pdb files found for input assemblies, default=true -->
|
||||
<ILMergeDebugInfo></ILMergeDebugInfo>
|
||||
|
||||
<!-- Target assembly will be delay signed -->
|
||||
<ILMergeDelaySign></ILMergeDelaySign>
|
||||
|
||||
<!-- Types in assemblies other than the primary assembly have their visibility modified -->
|
||||
<ILMergeInternalize></ILMergeInternalize>
|
||||
|
||||
<!-- The path name of the file that will be used to identify types that are not to have their visibility modified -->
|
||||
<ILMergeInternalizeExcludeFile></ILMergeInternalizeExcludeFile>
|
||||
|
||||
<!-- XML documentation files are merged to produce an XML documentation file for the target assembly -->
|
||||
<ILMergeXmlDocumentation></ILMergeXmlDocumentation>
|
||||
|
||||
<!-- External assembly references in the manifest of the target assembly will use full public keys (false) or public key tokens (true, default value) -->
|
||||
<ILMergePublicKeyTokens></ILMergePublicKeyTokens>
|
||||
|
||||
<!-- Types with the same name are all merged into a single type in the target assembly -->
|
||||
<ILMergeUnionMerge></ILMergeUnionMerge>
|
||||
|
||||
<!-- The version of the target framework, default 40 (works for 45 too) -->
|
||||
<ILTargetPlatform></ILTargetPlatform>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
# this file contains the partial list of the merged assemblies in the merge order
|
||||
# you can fill it from the obj\CONFIG\PROJECT.ilmerge generated on every build
|
||||
# and finetune merge order to your satisfaction
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public interface IMtApiServer
|
||||
{
|
||||
MtResponse SendCommand(MtCommand command);
|
||||
IEnumerable<MtQuote> GetQuotes();
|
||||
List<MtQuote> GetQuotes();
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using log4net;
|
||||
using log4net.Appender;
|
||||
using log4net.Core;
|
||||
using log4net.Layout;
|
||||
using log4net.Repository.Hierarchy;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public class LogConfigurator
|
||||
{
|
||||
private const string LogFileNameExtension = "txt";
|
||||
|
||||
public static void Setup(string profileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(profileName))
|
||||
throw new ArgumentNullException();
|
||||
|
||||
var hierarchy = (Hierarchy) LogManager.GetRepository();
|
||||
|
||||
var patternLayout = new PatternLayout
|
||||
{
|
||||
ConversionPattern = "%date [%thread] %-5level %logger - %message%newline"
|
||||
};
|
||||
patternLayout.ActivateOptions();
|
||||
|
||||
string filename = $"{DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss")}.{LogFileNameExtension}";
|
||||
|
||||
var roller = new RollingFileAppender
|
||||
{
|
||||
AppendToFile = false,
|
||||
File = $@"{System.IO.Path.GetTempPath()}{profileName}\Logs\{filename}",
|
||||
Layout = patternLayout,
|
||||
PreserveLogFileNameExtension = true,
|
||||
MaxSizeRollBackups = 5,
|
||||
MaximumFileSize = "1GB",
|
||||
RollingStyle = RollingFileAppender.RollingMode.Size,
|
||||
StaticLogFileName = false
|
||||
};
|
||||
roller.ActivateOptions();
|
||||
hierarchy.Root.AddAppender(roller);
|
||||
|
||||
var memory = new MemoryAppender();
|
||||
memory.ActivateOptions();
|
||||
hierarchy.Root.AddAppender(memory);
|
||||
|
||||
#if (DEBUG)
|
||||
hierarchy.Root.Level = Level.Debug;
|
||||
#else
|
||||
hierarchy.Root.Level = Level.Info;
|
||||
#endif
|
||||
hierarchy.Configured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props" Condition="Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
@@ -14,6 +15,8 @@
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile>
|
||||
</TargetFrameworkProfile>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -35,12 +38,17 @@
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>MtApiKey.pfx</AssemblyOriginatorKeyFile>
|
||||
<AssemblyOriginatorKeyFile>
|
||||
</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\log4net.2.0.5\lib\net40-full\log4net.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
@@ -54,6 +62,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="ICommandManager.cs" />
|
||||
<Compile Include="IMetaTraderHandler.cs" />
|
||||
<Compile Include="LogConfigurator.cs" />
|
||||
<Compile Include="MtCommandEventArgs.cs" />
|
||||
<Compile Include="IDisposableChannel.cs" />
|
||||
<Compile Include="IMtApiServer.cs" />
|
||||
@@ -78,13 +87,28 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="MtApiKey.pfx" />
|
||||
<None Include="ILMerge.props">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="MtApiKey.snk" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="ILMergeOrder.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets" Condition="Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.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">
|
||||
|
||||
Binary file not shown.
Executable
BIN
Binary file not shown.
+11
-14
@@ -1,20 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
class MtApiProxy : DuplexClientBase<IMtApi>, IMtApi, IDisposable
|
||||
internal class MtApiProxy : DuplexClientBase<IMtApi>, IMtApi, IDisposable
|
||||
{
|
||||
public MtApiProxy(InstanceContext callbackContext, Binding binding,
|
||||
EndpointAddress remoteAddress)
|
||||
public MtApiProxy(InstanceContext callbackContext, Binding binding, EndpointAddress remoteAddress)
|
||||
: base(callbackContext, binding, remoteAddress)
|
||||
{
|
||||
base.InnerDuplexChannel.Faulted += new EventHandler(InnerDuplexChannel_Faulted);
|
||||
base.InnerDuplexChannel.Open();
|
||||
InnerDuplexChannel.Faulted += InnerDuplexChannel_Faulted;
|
||||
InnerDuplexChannel.Open();
|
||||
}
|
||||
|
||||
#region IMtApi Members
|
||||
@@ -34,7 +31,7 @@ namespace MTApiService
|
||||
return Channel.SendCommand(command);
|
||||
}
|
||||
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
public List<MtQuote> GetQuotes()
|
||||
{
|
||||
return Channel.GetQuotes();
|
||||
}
|
||||
@@ -47,19 +44,19 @@ namespace MTApiService
|
||||
{
|
||||
try
|
||||
{
|
||||
this.Close();
|
||||
Close();
|
||||
}
|
||||
catch (CommunicationException)
|
||||
{
|
||||
this.Abort();
|
||||
Abort();
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
this.Abort();
|
||||
Abort();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
this.Abort();
|
||||
Abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +65,9 @@ namespace MTApiService
|
||||
#region Private Methods
|
||||
private void InnerDuplexChannel_Faulted(object sender, EventArgs e)
|
||||
{
|
||||
if (Faulted != null)
|
||||
Faulted(this, e);
|
||||
Faulted?.Invoke(this, e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
+108
-35
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Collections;
|
||||
using System.ServiceModel;
|
||||
using System.Collections.Generic;
|
||||
using log4net;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
@@ -14,6 +14,8 @@ namespace MTApiService
|
||||
public delegate void MtQuoteHandler(MtQuote quote);
|
||||
|
||||
#region Fields
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtClient));
|
||||
|
||||
private MtApiProxy _proxy;
|
||||
private bool _isConnected;
|
||||
#endregion
|
||||
@@ -21,7 +23,7 @@ namespace MTApiService
|
||||
#region Public Methods
|
||||
public void Open(string host, int port)
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::Open");
|
||||
Log.DebugFormat("Open: begin. host = {0}, port = {1}", host, port);
|
||||
|
||||
if (string.IsNullOrEmpty(host))
|
||||
throw new ArgumentNullException(nameof(host), "host is null or empty");
|
||||
@@ -32,7 +34,10 @@ namespace MTApiService
|
||||
var urlService = $"net.tcp://{host}:{port}/{ServiceName}";
|
||||
|
||||
if (_proxy != null)
|
||||
{
|
||||
Log.Warn("Open: end. _proxy is not null.");
|
||||
return;
|
||||
}
|
||||
|
||||
var bind = new NetTcpBinding(SecurityMode.None)
|
||||
{
|
||||
@@ -52,17 +57,24 @@ namespace MTApiService
|
||||
|
||||
_proxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
|
||||
_proxy.Faulted += ProxyFaulted;
|
||||
|
||||
Log.Debug("Open: end.");
|
||||
}
|
||||
|
||||
public void Open(int port)
|
||||
{
|
||||
Log.DebugFormat("Open: begin. port = {0}", port);
|
||||
|
||||
if (port < 0 || port > 65536)
|
||||
throw new ArgumentOutOfRangeException(nameof(port), "port value is invalid");
|
||||
|
||||
var urlService = $"net.pipe://localhost/{ServiceName}_{port}";
|
||||
|
||||
if (_proxy != null)
|
||||
{
|
||||
Log.Warn("Open: end. _proxy is not null.");
|
||||
return;
|
||||
}
|
||||
|
||||
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
|
||||
{
|
||||
@@ -82,11 +94,13 @@ namespace MTApiService
|
||||
|
||||
_proxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
|
||||
_proxy.Faulted += ProxyFaulted;
|
||||
|
||||
Log.Debug("Open: end.");
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::Close");
|
||||
Log.Debug("Close: begin.");
|
||||
|
||||
if (_proxy != null)
|
||||
{
|
||||
@@ -96,35 +110,52 @@ namespace MTApiService
|
||||
}
|
||||
|
||||
_isConnected = false;
|
||||
|
||||
Log.Debug("Close: end.");
|
||||
}
|
||||
|
||||
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
|
||||
public void Connect()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::Connect");
|
||||
Log.Debug("Connect: begin.");
|
||||
|
||||
if (_proxy == null)
|
||||
{
|
||||
Log.Error("Connect: _proxy is not defined.");
|
||||
throw new CommunicationException("Connection failed to service. Proxy is not defined (needs to call Open)");
|
||||
}
|
||||
|
||||
if (_isConnected)
|
||||
{
|
||||
Log.Warn("Connected: end. Client is already connected.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_proxy != null && _isConnected)
|
||||
return;
|
||||
|
||||
_isConnected = _proxy.Connect();
|
||||
|
||||
if (_isConnected == false)
|
||||
throw new Exception("Connected failed");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("[ERROR] MtClient::Connect: {0}", ex.Message);
|
||||
Log.ErrorFormat("Connect: Exception - {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
|
||||
throw new CommunicationException("Connection failed to service");
|
||||
throw new CommunicationException($"Connection failed to service. {ex.Message}");
|
||||
}
|
||||
|
||||
if (_isConnected == false)
|
||||
{
|
||||
Log.Error("Connect: end. Connection failed.");
|
||||
throw new CommunicationException("Connection failed");
|
||||
}
|
||||
|
||||
Log.Debug("Connect: end.");
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::Disconnect");
|
||||
Log.Debug("Disconnect: begin.");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -134,26 +165,40 @@ namespace MTApiService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("[ERROR] MtClient::Disconnect: {0}", ex.Message);
|
||||
Log.ErrorFormat("Disconnect: Exception - {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
Log.Debug("Disconnect: end.");
|
||||
}
|
||||
|
||||
public MtResponse SendCommand(int commandType, ArrayList commandParameters)
|
||||
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
|
||||
public MtResponse SendCommand(int commandType, ArrayList parameters)
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::SendCommand: commandType = {0}", commandType);
|
||||
Log.DebugFormat("SendCommand: begin. commandType = {0}, parameters count = {1}", commandType, parameters?.Count);
|
||||
|
||||
MtResponse result = null;
|
||||
MtResponse result;
|
||||
|
||||
if (_proxy == null)
|
||||
{
|
||||
Log.Error("SendCommand: Proxy is not defined.");
|
||||
throw new CommunicationException("Proxy is not defined.");
|
||||
}
|
||||
|
||||
if (_isConnected == false)
|
||||
{
|
||||
Log.Error("SendCommand: Client is not connected.");
|
||||
throw new CommunicationException("Client is not connected.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_proxy != null && _isConnected)
|
||||
result = _proxy.SendCommand(new MtCommand(commandType, commandParameters));
|
||||
result = _proxy.SendCommand(new MtCommand(commandType, parameters));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("[ERROR] MtClient::SendCommand: {0}", ex.Message);
|
||||
Log.ErrorFormat("SendCommand: Exception - {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
|
||||
@@ -163,27 +208,41 @@ namespace MTApiService
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::GetQuotes");
|
||||
Log.Debug("GetQuotes: begin.");
|
||||
|
||||
IEnumerable<MtQuote> result = null;
|
||||
if (_proxy == null)
|
||||
{
|
||||
Log.Warn("GetQuotes: end. _proxy is not defined.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_isConnected == false)
|
||||
{
|
||||
Log.Warn("GetQuotes: end. Client is not connected.");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<MtQuote> result;
|
||||
|
||||
try
|
||||
{
|
||||
if (_proxy != null && _isConnected)
|
||||
result = _proxy.GetQuotes();
|
||||
result = _proxy.GetQuotes();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("[ERROR] MtClient::GetQuotes: {0}", ex.Message);
|
||||
Log.ErrorFormat("GetQuotes: Exception - {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
|
||||
throw new CommunicationException("Service connection failed");
|
||||
throw new CommunicationException($"Service connection failed! {ex.Message}");
|
||||
}
|
||||
|
||||
return result;;
|
||||
Log.DebugFormat("GetQuotes: end. quotes count = {0}", result?.Count);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -192,40 +251,51 @@ namespace MTApiService
|
||||
|
||||
public void OnQuoteUpdate(MtQuote quote)
|
||||
{
|
||||
Log.DebugFormat("OnQuoteUpdate: begin. quote = {0}", quote);
|
||||
|
||||
if (quote == null) return;
|
||||
|
||||
QuoteUpdated?.Invoke(quote);
|
||||
|
||||
Debug.WriteLine("[INFO] MtClient::OnQuoteUpdate: " + quote);
|
||||
Log.Debug("OnQuoteUpdate: end.");
|
||||
}
|
||||
|
||||
public void OnQuoteAdded(MtQuote quote)
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::OnQuoteAdded");
|
||||
Log.DebugFormat("OnQuoteAdded: begin. quote = {0}", quote);
|
||||
|
||||
QuoteAdded?.Invoke(quote);
|
||||
|
||||
Log.Debug("OnQuoteAdded: end.");
|
||||
}
|
||||
|
||||
public void OnQuoteRemoved(MtQuote quote)
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::OnQuoteRemoved");
|
||||
Log.DebugFormat("OnQuoteRemoved: begin. quote = {0}", quote);
|
||||
|
||||
QuoteRemoved?.Invoke(quote);
|
||||
|
||||
Log.Debug("OnQuoteRemoved: end.");
|
||||
}
|
||||
|
||||
public void OnServerStopped()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::OnServerStopped");
|
||||
Log.Debug("OnServerStopped: begin.");
|
||||
|
||||
Close();
|
||||
|
||||
ServerDisconnected?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
Log.Debug("OnServerStopped: end.");
|
||||
}
|
||||
|
||||
|
||||
public void OnMtEvent(MtEvent mtEvent)
|
||||
{
|
||||
Log.DebugFormat("OnMtEvent: begin. event = {0}", mtEvent);
|
||||
|
||||
MtEventReceived?.Invoke(this, new MtEventArgs(mtEvent));
|
||||
|
||||
Log.Debug("OnMtEvent: end.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -239,11 +309,12 @@ namespace MTApiService
|
||||
|
||||
private void ProxyFaulted(object sender, EventArgs e)
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::ProxyFaulted");
|
||||
Log.Debug("ProxyFaulted: begin.");
|
||||
|
||||
Close();
|
||||
|
||||
ServerFailed?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
Log.Debug("ProxyFaulted: end.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -252,9 +323,11 @@ namespace MTApiService
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::Dispose");
|
||||
Log.Debug("Dispose: begin.");
|
||||
|
||||
Close();
|
||||
|
||||
Log.Debug("Dispose: end.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ServiceModel;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Collections;
|
||||
|
||||
namespace MTApiService
|
||||
@@ -22,5 +18,9 @@ namespace MTApiService
|
||||
[DataMember]
|
||||
public ArrayList Parameters { get; private set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"CommandType = {CommandType}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Regular → Executable
+11
-3
@@ -1,4 +1,5 @@
|
||||
using System.Threading;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
@@ -10,6 +11,9 @@ namespace MTApiService
|
||||
|
||||
public MtCommandTask(MtCommand command)
|
||||
{
|
||||
if (command == null)
|
||||
throw new ArgumentNullException(nameof(command));
|
||||
|
||||
Command = command;
|
||||
}
|
||||
|
||||
@@ -20,7 +24,7 @@ namespace MTApiService
|
||||
_responseWaiter.WaitOne(time);
|
||||
lock (_locker)
|
||||
{
|
||||
return _result;
|
||||
return _result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +36,10 @@ namespace MTApiService
|
||||
}
|
||||
_responseWaiter.Set();
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Command = {Command}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public class MtConnectionProfile
|
||||
|
||||
@@ -1,31 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using log4net;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
internal class MtCommandExecutorManager : ICommandManager
|
||||
{
|
||||
#region Private Fields
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtCommandExecutorManager));
|
||||
|
||||
private readonly List<MtExpert> _commandExecutors = new List<MtExpert>();
|
||||
private readonly Queue<MtCommandTask> _commandTasks = new Queue<MtCommandTask>();
|
||||
|
||||
private readonly object _locker = new object();
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
Log.Debug("Stop: begin.");
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
_commandExecutors.Clear();
|
||||
_commandTasks.Clear();
|
||||
}
|
||||
|
||||
Log.Debug("Stop: end.");
|
||||
}
|
||||
|
||||
public void AddCommandExecutor(MtExpert commandExecutor)
|
||||
{
|
||||
if (commandExecutor == null)
|
||||
return;
|
||||
throw new ArgumentNullException(nameof(commandExecutor));
|
||||
|
||||
Log.DebugFormat("AddCommandExecutor: begin. commandExecutor = {0}", commandExecutor);
|
||||
|
||||
var notify = false;
|
||||
lock (_locker)
|
||||
{
|
||||
if (_commandExecutors.Contains(commandExecutor))
|
||||
{
|
||||
Log.Warn("AddCommandExecutor: end. Command executor already exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
_commandExecutors.Add(commandExecutor);
|
||||
if (_commandTasks.Count > 0)
|
||||
@@ -41,18 +60,25 @@ namespace MTApiService
|
||||
{
|
||||
NotifyCommandReady();
|
||||
}
|
||||
|
||||
Log.Debug("AddCommandExecutor: end.");
|
||||
}
|
||||
|
||||
public void RemoveCommandExecutor(MtExpert commandExecutor)
|
||||
{
|
||||
if (commandExecutor == null)
|
||||
return;
|
||||
throw new ArgumentNullException(nameof(commandExecutor));
|
||||
|
||||
Log.DebugFormat("RemoveCommandExecutor: begin. commandExecutor = {0}", commandExecutor);
|
||||
|
||||
var notify = false;
|
||||
lock (_locker)
|
||||
{
|
||||
if (_commandExecutors.Contains(commandExecutor) == false)
|
||||
{
|
||||
Log.Warn("RemoveCommandExecutor: end. Command executor is not exist in collection.");
|
||||
return;
|
||||
}
|
||||
|
||||
_commandExecutors.Remove(commandExecutor);
|
||||
if (_commandTasks.Count > 0)
|
||||
@@ -68,23 +94,31 @@ namespace MTApiService
|
||||
{
|
||||
NotifyCommandReady();
|
||||
}
|
||||
|
||||
Log.Debug("RemoveCommandExecutor: end.");
|
||||
}
|
||||
|
||||
public void EnqueueCommandTask(MtCommandTask task)
|
||||
{
|
||||
if (task == null)
|
||||
return;
|
||||
throw new ArgumentNullException(nameof(task));
|
||||
|
||||
Log.DebugFormat("EnqueueCommandTask: begin. task = {0}", task);
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
_commandTasks.Enqueue(task);
|
||||
_commandTasks.Enqueue(task);
|
||||
}
|
||||
|
||||
NotifyCommandReady();
|
||||
|
||||
Log.Debug("EnqueueCommandTask: end.");
|
||||
}
|
||||
|
||||
public MtCommandTask DequeueCommandTask()
|
||||
{
|
||||
Log.Debug("DequeueCommandTask: called.");
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
return _commandTasks.Count > 0 ? _commandTasks.Dequeue() : null;
|
||||
@@ -96,6 +130,8 @@ namespace MTApiService
|
||||
#region Private Methods
|
||||
private void NotifyCommandReady()
|
||||
{
|
||||
Log.Debug("NotifyCommandReady: begin.");
|
||||
|
||||
var commandExecutors = new List<MtExpert>();
|
||||
lock (_locker)
|
||||
{
|
||||
@@ -106,10 +142,14 @@ namespace MTApiService
|
||||
{
|
||||
executor.NotifyCommandReady();
|
||||
}
|
||||
|
||||
Log.DebugFormat("NotifyCommandReady: end. Notified executor count = {0}", commandExecutors.Count);
|
||||
}
|
||||
|
||||
private void CommandExecutor_CommandExecuted(object sender, EventArgs e)
|
||||
{
|
||||
Log.Debug("CommandExecutor_CommandExecuted: begin.");
|
||||
|
||||
var notify = false;
|
||||
lock (_locker)
|
||||
{
|
||||
@@ -124,14 +164,8 @@ namespace MTApiService
|
||||
NotifyCommandReady();
|
||||
}
|
||||
|
||||
Log.Debug("CommandExecutor_CommandExecuted: end.");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private readonly List<MtExpert> _commandExecutors = new List<MtExpert>();
|
||||
private readonly Queue<MtCommandTask> _commandTasks = new Queue<MtCommandTask>();
|
||||
|
||||
private readonly object _locker = new object();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
+93
-68
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using log4net;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
@@ -6,20 +7,103 @@ namespace MTApiService
|
||||
{
|
||||
public delegate void MtQuoteHandler(MtExpert expert, MtQuote quote);
|
||||
|
||||
#region Private Fields
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtExpert));
|
||||
|
||||
private readonly IMetaTraderHandler _mtHadler;
|
||||
private MtCommandTask _commandTask;
|
||||
private ICommandManager _commandManager;
|
||||
private readonly object _locker = new object();
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public MtExpert(int handle, MtQuote quote, IMetaTraderHandler mtHandler)
|
||||
{
|
||||
if (mtHandler == null)
|
||||
throw new ArgumentNullException(nameof(mtHandler));
|
||||
|
||||
Quote = quote;
|
||||
Handle = handle;
|
||||
_mtHadler = mtHandler;
|
||||
}
|
||||
|
||||
public void Deinit()
|
||||
{
|
||||
Log.Debug("Deinit: begin.");
|
||||
|
||||
IsEnable = false;
|
||||
FireOnDeinited();
|
||||
|
||||
Log.Debug("Deinit: end.");
|
||||
}
|
||||
|
||||
public void SendResponse(MtResponse response)
|
||||
{
|
||||
Log.DebugFormat("SendResponse: begin. response = {0}", response);
|
||||
|
||||
_commandTask.SetResult(response);
|
||||
_commandTask = null;
|
||||
FireOnCommandExecuted();
|
||||
|
||||
Log.Debug("SendResponse: end.");
|
||||
}
|
||||
|
||||
public int GetCommandType()
|
||||
{
|
||||
Log.Debug("GetCommandType: called.");
|
||||
|
||||
var commandManager = CommandManager;
|
||||
if (commandManager != null)
|
||||
{
|
||||
_commandTask = commandManager.DequeueCommandTask();
|
||||
}
|
||||
|
||||
return _commandTask?.Command?.CommandType ?? 0;
|
||||
}
|
||||
|
||||
public object GetCommandParameter(int index)
|
||||
{
|
||||
Log.DebugFormat("GetCommandType: called. index = {0}", index);
|
||||
|
||||
var command = _commandTask?.Command;
|
||||
if (command?.Parameters != null && index >= 0 && index < command.Parameters.Count)
|
||||
{
|
||||
return command.Parameters[index];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SendEvent(MtEvent mtEvent)
|
||||
{
|
||||
Log.DebugFormat("SendEvent: begin. event = {0}", mtEvent);
|
||||
|
||||
FireOnMtEvent(mtEvent);
|
||||
|
||||
Log.Debug("SendEvent: end.");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"ExpertHandle = {Handle}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
private MtQuote _quote;
|
||||
public MtQuote Quote
|
||||
public MtQuote Quote
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
return _quote;
|
||||
return _quote;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock(_locker)
|
||||
lock (_locker)
|
||||
{
|
||||
_quote = value;
|
||||
}
|
||||
@@ -28,7 +112,7 @@ namespace MTApiService
|
||||
}
|
||||
}
|
||||
|
||||
public int Handle { get; private set; }
|
||||
public int Handle { get; }
|
||||
|
||||
private bool _isEnable = true;
|
||||
public bool IsEnable
|
||||
@@ -69,73 +153,21 @@ namespace MTApiService
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public MtExpert(int handle, MtQuote quote, IMetaTraderHandler mtHandler)
|
||||
{
|
||||
Quote = quote;
|
||||
Handle = handle;
|
||||
_mtHadler = mtHandler;
|
||||
}
|
||||
|
||||
public void Deinit()
|
||||
{
|
||||
IsEnable = false;
|
||||
FireOnDeinited();
|
||||
}
|
||||
|
||||
public void SendResponse(MtResponse response)
|
||||
{
|
||||
_commandTask.SetResult(response);
|
||||
_commandTask = null;
|
||||
FireOnCommandExecuted();
|
||||
}
|
||||
|
||||
public int GetCommandType()
|
||||
{
|
||||
var commandManager = CommandManager;
|
||||
if (commandManager != null)
|
||||
{
|
||||
_commandTask = commandManager.DequeueCommandTask();
|
||||
}
|
||||
|
||||
return _commandTask != null && _commandTask.Command != null ? _commandTask.Command.CommandType : 0;
|
||||
}
|
||||
|
||||
public object GetCommandParameter(int index)
|
||||
{
|
||||
if (_commandTask != null)
|
||||
{
|
||||
var command = _commandTask.Command;
|
||||
if (command != null && command.Parameters != null
|
||||
&& index >= 0 && index < command.Parameters.Count)
|
||||
{
|
||||
return command.Parameters[index];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SendEvent(MtEvent mtEvent)
|
||||
{
|
||||
FireOnMtEvent(mtEvent);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IMtCommandExecutor
|
||||
public void NotifyCommandReady()
|
||||
{
|
||||
Log.Debug("NotifyCommandReady: begin.");
|
||||
|
||||
SendTickToMetaTrader();
|
||||
|
||||
Log.Debug("NotifyCommandReady: end.");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private void SendTickToMetaTrader()
|
||||
{
|
||||
if (_mtHadler != null)
|
||||
{
|
||||
_mtHadler.SendTickToMetaTrader(Handle);
|
||||
}
|
||||
_mtHadler.SendTickToMetaTrader(Handle);
|
||||
}
|
||||
|
||||
private void FireOnQuoteChanged(MtQuote quote)
|
||||
@@ -165,12 +197,5 @@ namespace MTApiService
|
||||
public event EventHandler CommandExecuted;
|
||||
public event EventHandler<MtEventArgs> OnMtEvent;
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private readonly IMetaTraderHandler _mtHadler;
|
||||
private MtCommandTask _commandTask;
|
||||
private ICommandManager _commandManager;
|
||||
private readonly object _locker = new object();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
@@ -10,34 +7,34 @@ namespace MTApiService
|
||||
public class MtMqlTradeRequest
|
||||
{
|
||||
[DataMember]
|
||||
public int Action { get; set; }
|
||||
public int Action { get; set; }
|
||||
[DataMember]
|
||||
public uint Magic { get; set; }
|
||||
public uint Magic { get; set; }
|
||||
[DataMember]
|
||||
public uint Order { get; set; }
|
||||
public uint Order { get; set; }
|
||||
[DataMember]
|
||||
public string Symbol { get; set; }
|
||||
public string Symbol { get; set; }
|
||||
[DataMember]
|
||||
public double Volume { get; set; }
|
||||
public double Volume { get; set; }
|
||||
[DataMember]
|
||||
public double Price { get; set; }
|
||||
public double Price { get; set; }
|
||||
[DataMember]
|
||||
public double Stoplimit { get; set; }
|
||||
public double Stoplimit { get; set; }
|
||||
[DataMember]
|
||||
public double Sl { get; set; }
|
||||
public double Sl { get; set; }
|
||||
[DataMember]
|
||||
public double Tp { get; set; }
|
||||
public double Tp { get; set; }
|
||||
[DataMember]
|
||||
public uint Deviation { get; set; }
|
||||
public uint Deviation { get; set; }
|
||||
[DataMember]
|
||||
public int Type { get; set; }
|
||||
public int Type { get; set; }
|
||||
[DataMember]
|
||||
public int Type_filling { get; set; }
|
||||
public int Type_filling { get; set; }
|
||||
[DataMember]
|
||||
public int Type_time { get; set; }
|
||||
public int Type_time { get; set; }
|
||||
[DataMember]
|
||||
public DateTime Expiration { get; set; }
|
||||
public DateTime Expiration { get; set; }
|
||||
[DataMember]
|
||||
public string Comment { get; set; }
|
||||
public string Comment { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Win32;
|
||||
using System.Diagnostics;
|
||||
|
||||
@@ -9,12 +7,12 @@ namespace MTApiService
|
||||
{
|
||||
public class MtRegistryManager
|
||||
{
|
||||
private const string SOFTWARE = "Software";
|
||||
private const string APP_NAME = "MtApi";
|
||||
private const string PROFILES_REGKEY = "ConnectionProfiles";
|
||||
private const string HOST_REGVALUE_NAME = "Host";
|
||||
private const string PORT_REGVALUE_NAME = "Port";
|
||||
private const string SIGNATURE_REGVALUE_NAME = "MtSignature";
|
||||
private const string Software = "Software";
|
||||
private const string AppName = "MtApi";
|
||||
private const string ProfilesRegkey = "ConnectionProfiles";
|
||||
private const string HostRegvalueName = "Host";
|
||||
private const string PortRegvalueName = "Port";
|
||||
private const string SignatureRegvalueName = "MtSignature";
|
||||
|
||||
#region Public Methods
|
||||
public static IEnumerable<MtConnectionProfile> LoadConnectionProfiles()
|
||||
@@ -53,12 +51,12 @@ namespace MTApiService
|
||||
|
||||
string signature = null;
|
||||
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
if (softwareRegKey != null)
|
||||
{
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
|
||||
if (appRegKey != null)
|
||||
{
|
||||
using (appRegKey)
|
||||
@@ -73,7 +71,7 @@ namespace MTApiService
|
||||
{
|
||||
using (numberKey)
|
||||
{
|
||||
signature = numberKey.GetValue(SIGNATURE_REGVALUE_NAME).ToString();
|
||||
signature = numberKey.GetValue(SignatureRegvalueName).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,7 +92,7 @@ namespace MTApiService
|
||||
return null;
|
||||
}
|
||||
|
||||
RegistryKey softwareRgKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
var softwareRgKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
|
||||
if (softwareRgKey == null)
|
||||
return null;
|
||||
@@ -105,35 +103,33 @@ namespace MTApiService
|
||||
{
|
||||
|
||||
//app name
|
||||
var appRegKey = softwareRgKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey == null)
|
||||
var appRegKey = softwareRgKey.OpenSubKey(AppName, true) ?? softwareRgKey.CreateSubKey(AppName);
|
||||
|
||||
if (appRegKey != null)
|
||||
{
|
||||
appRegKey = softwareRgKey.CreateSubKey(APP_NAME);
|
||||
}
|
||||
|
||||
using (appRegKey)
|
||||
{
|
||||
//account name
|
||||
var accountKey = appRegKey.OpenSubKey(accountName, true);
|
||||
if (accountKey == null)
|
||||
using (appRegKey)
|
||||
{
|
||||
accountKey = appRegKey.CreateSubKey(accountName);
|
||||
}
|
||||
//account name
|
||||
var accountKey = appRegKey.OpenSubKey(accountName, true) ?? appRegKey.CreateSubKey(accountName);
|
||||
|
||||
using (accountKey)
|
||||
{
|
||||
//account number
|
||||
var numberKey = accountKey.OpenSubKey(accountNumber, true);
|
||||
if (numberKey == null)
|
||||
if (accountKey != null)
|
||||
{
|
||||
numberKey = accountKey.CreateSubKey(accountNumber);
|
||||
}
|
||||
using (accountKey)
|
||||
{
|
||||
//account number
|
||||
var numberKey = accountKey.OpenSubKey(accountNumber, true) ??
|
||||
accountKey.CreateSubKey(accountNumber);
|
||||
|
||||
using (numberKey)
|
||||
{
|
||||
numberKey.SetValue(SIGNATURE_REGVALUE_NAME, signature);
|
||||
if (numberKey != null)
|
||||
{
|
||||
using (numberKey)
|
||||
{
|
||||
numberKey.SetValue(SignatureRegvalueName, signature);
|
||||
|
||||
retVal = numberKey.ToString();
|
||||
retVal = numberKey.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,20 +138,19 @@ namespace MTApiService
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static bool ExportKey(string RegKey, string SavePath)
|
||||
public static bool ExportKey(string regKey, string savePath)
|
||||
{
|
||||
string path = "\"" + SavePath + "\"";
|
||||
string key = "\"" + RegKey + "\"";
|
||||
var path = $"\"{savePath}\"";
|
||||
var key = $"\"{regKey}\"";
|
||||
|
||||
Process proc = new Process();
|
||||
var proc = new Process();
|
||||
try
|
||||
{
|
||||
proc.StartInfo.FileName = "regedit.exe";
|
||||
proc.StartInfo.UseShellExecute = false;
|
||||
proc = Process.Start("regedit.exe", "/e " + path + " " + key + "");
|
||||
|
||||
if (proc != null)
|
||||
proc.WaitForExit();
|
||||
proc?.WaitForExit();
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
@@ -163,8 +158,7 @@ namespace MTApiService
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (proc != null)
|
||||
proc.Dispose();
|
||||
proc?.Dispose();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -177,33 +171,38 @@ namespace MTApiService
|
||||
{
|
||||
List<MtConnectionProfile> profiles = null;
|
||||
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
if (softwareRegKey != null)
|
||||
{
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
|
||||
if (appRegKey != null)
|
||||
{
|
||||
using (appRegKey)
|
||||
{
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true);
|
||||
if (profilesRegKey != null)
|
||||
{
|
||||
using (profilesRegKey)
|
||||
{
|
||||
profiles = new List<MtConnectionProfile>();
|
||||
|
||||
foreach (string profileNameKey in profilesRegKey.GetSubKeyNames())
|
||||
foreach (var profileNameKey in profilesRegKey.GetSubKeyNames())
|
||||
{
|
||||
using (RegistryKey tempKey = profilesRegKey.OpenSubKey(profileNameKey))
|
||||
var tempKey = profilesRegKey.OpenSubKey(profileNameKey);
|
||||
if (tempKey != null)
|
||||
{
|
||||
var profile = new MtConnectionProfile(profileNameKey);
|
||||
using (tempKey)
|
||||
{
|
||||
var profile = new MtConnectionProfile(profileNameKey)
|
||||
{
|
||||
Host = tempKey.GetValue(HostRegvalueName).ToString(),
|
||||
Port = (int) tempKey.GetValue(PortRegvalueName)
|
||||
};
|
||||
|
||||
profile.Host = tempKey.GetValue(HOST_REGVALUE_NAME).ToString();
|
||||
profile.Port = (int)tempKey.GetValue(PORT_REGVALUE_NAME);
|
||||
|
||||
profiles.Add(profile);
|
||||
profiles.Add(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,27 +219,33 @@ namespace MTApiService
|
||||
{
|
||||
MtConnectionProfile profile = null;
|
||||
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
if (softwareRegKey != null)
|
||||
{
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
|
||||
if (appRegKey != null)
|
||||
{
|
||||
using (appRegKey)
|
||||
{
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true);
|
||||
if (profilesRegKey != null)
|
||||
{
|
||||
using (profilesRegKey)
|
||||
{
|
||||
using (RegistryKey tempKey = profilesRegKey.OpenSubKey(profileName))
|
||||
var tempKey = profilesRegKey.OpenSubKey(profileName);
|
||||
if (tempKey != null)
|
||||
{
|
||||
profile = new MtConnectionProfile(profileName);
|
||||
using (tempKey)
|
||||
{
|
||||
profile = new MtConnectionProfile(profileName)
|
||||
{
|
||||
Host = tempKey.GetValue(HostRegvalueName).ToString(),
|
||||
Port = (int) tempKey.GetValue(PortRegvalueName)
|
||||
};
|
||||
|
||||
profile.Host = tempKey.GetValue(HOST_REGVALUE_NAME).ToString();
|
||||
profile.Port = (int)tempKey.GetValue(PORT_REGVALUE_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,7 +259,7 @@ namespace MTApiService
|
||||
|
||||
private static void SaveConnectionProfileToRegistry(MtConnectionProfile profile)
|
||||
{
|
||||
RegistryKey softwareRgKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
var softwareRgKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
|
||||
if (softwareRgKey == null)
|
||||
return;
|
||||
@@ -262,29 +267,30 @@ namespace MTApiService
|
||||
using (softwareRgKey)
|
||||
{
|
||||
//app name
|
||||
var appRegKey = softwareRgKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey == null)
|
||||
var appRegKey = softwareRgKey.OpenSubKey(AppName, true) ?? softwareRgKey.CreateSubKey(AppName);
|
||||
|
||||
if (appRegKey != null)
|
||||
{
|
||||
appRegKey = softwareRgKey.CreateSubKey(APP_NAME);
|
||||
}
|
||||
|
||||
using (appRegKey)
|
||||
{
|
||||
//ConnectionProfiles key
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
if (profilesRegKey == null)
|
||||
using (appRegKey)
|
||||
{
|
||||
profilesRegKey = appRegKey.CreateSubKey(PROFILES_REGKEY);
|
||||
}
|
||||
//ConnectionProfiles key
|
||||
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true) ??
|
||||
appRegKey.CreateSubKey(ProfilesRegkey);
|
||||
|
||||
using (profilesRegKey)
|
||||
{
|
||||
var profileKey = profilesRegKey.CreateSubKey(profile.Name);
|
||||
|
||||
using (profileKey)
|
||||
if (profilesRegKey != null)
|
||||
{
|
||||
profileKey.SetValue(HOST_REGVALUE_NAME, profile.Host);
|
||||
profileKey.SetValue(PORT_REGVALUE_NAME, profile.Port);
|
||||
using (profilesRegKey)
|
||||
{
|
||||
var profileKey = profilesRegKey.CreateSubKey(profile.Name);
|
||||
if (profileKey != null)
|
||||
{
|
||||
using (profileKey)
|
||||
{
|
||||
profileKey.SetValue(HostRegvalueName, profile.Host);
|
||||
profileKey.SetValue(PortRegvalueName, profile.Port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,19 +299,19 @@ namespace MTApiService
|
||||
|
||||
private static void DeleteConnectionProfileFromRegistry(string profileName)
|
||||
{
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
if (softwareRegKey == null)
|
||||
return;
|
||||
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
|
||||
if (appRegKey == null)
|
||||
return;
|
||||
|
||||
using (appRegKey)
|
||||
{
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true);
|
||||
if (profilesRegKey == null)
|
||||
return;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
@@ -35,6 +36,11 @@ namespace MTApiService
|
||||
public int Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -49,6 +55,11 @@ namespace MTApiService
|
||||
public long Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -63,6 +74,11 @@ namespace MTApiService
|
||||
public ulong Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -77,6 +93,11 @@ namespace MTApiService
|
||||
public double Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString(CultureInfo.CurrentCulture);
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -91,6 +112,11 @@ namespace MTApiService
|
||||
public string Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -105,6 +131,11 @@ namespace MTApiService
|
||||
public bool Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -119,6 +150,11 @@ namespace MTApiService
|
||||
public double[] Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -133,6 +169,11 @@ namespace MTApiService
|
||||
public int[] Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -147,6 +188,11 @@ namespace MTApiService
|
||||
public long[] Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -161,6 +207,11 @@ namespace MTApiService
|
||||
public ArrayList Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -175,6 +226,11 @@ namespace MTApiService
|
||||
public MtMqlRates[] Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -189,6 +245,11 @@ namespace MTApiService
|
||||
public MtMqlTick Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -203,6 +264,11 @@ namespace MTApiService
|
||||
public MtMqlBookInfo[] Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+193
-107
@@ -3,17 +3,26 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.ServiceModel;
|
||||
using System.Net;
|
||||
using System.Diagnostics;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.Net.Sockets;
|
||||
using log4net;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
internal class MtServer : IDisposable, IMtApiServer
|
||||
{
|
||||
#region Constants
|
||||
private const int WAIT_RESPONSE_TIME = 40000; // 40 sec
|
||||
private const int STOP_EXPERT_INTERVAL = 1000; // 1 sec
|
||||
private const int WaitResponseTime = 40000; // 40 sec
|
||||
private const int StopExpertInterval = 1000; // 1 sec
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtServer));
|
||||
|
||||
private readonly MtService _service;
|
||||
private readonly List<ServiceHost> _hosts = new List<ServiceHost>();
|
||||
private readonly MtCommandExecutorManager _executorManager = new MtCommandExecutorManager();
|
||||
private readonly List<MtExpert> _experts = new List<MtExpert>();
|
||||
#endregion
|
||||
|
||||
#region ctor
|
||||
@@ -25,99 +34,126 @@ namespace MTApiService
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public int Port { get; private set; }
|
||||
public int Port { get; }
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void Start()
|
||||
{
|
||||
Log.Debug("Start: begin");
|
||||
|
||||
var hostsInitialized = InitHosts(Port);
|
||||
if (hostsInitialized == false)
|
||||
{
|
||||
Debug.WriteLine("Start: InitHosts failed. ");
|
||||
}
|
||||
|
||||
Log.DebugFormat("Start: end. hostsInitialized = {0}", hostsInitialized);
|
||||
}
|
||||
|
||||
private bool InitHosts(int port)
|
||||
{
|
||||
Log.DebugFormat("InitHosts: begin. port = {0}", port);
|
||||
|
||||
int count;
|
||||
|
||||
lock (_hosts)
|
||||
{
|
||||
if (_hosts.Count > 0)
|
||||
{
|
||||
Log.Info("InitHosts: end. Host's has been initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
//init local pipe host
|
||||
string localUrl = CreateConnectionAddress(null, port, true);
|
||||
ServiceHost localServiceHost = CreateServiceHost(localUrl, true);
|
||||
var localUrl = CreateConnectionAddress(null, port, true);
|
||||
var localServiceHost = CreateServiceHost(localUrl, true);
|
||||
if (localServiceHost != null)
|
||||
{
|
||||
_hosts.Add(localServiceHost);
|
||||
}
|
||||
|
||||
//init network hosts
|
||||
IPHostEntry ips = Dns.GetHostEntry(Dns.GetHostName());
|
||||
if (ips != null)
|
||||
var dnsHostName = Dns.GetHostName();
|
||||
var ips = Dns.GetHostEntry(dnsHostName);
|
||||
if (ips == null)
|
||||
{
|
||||
foreach (IPAddress ipAddress in ips.AddressList)
|
||||
Log.WarnFormat("InitHosts: end. Dns.GetHostEntry has returned null for DNS Host Name {0}", dnsHostName);
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var ipAddress in ips.AddressList)
|
||||
{
|
||||
if (ipAddress?.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
if (ipAddress != null)
|
||||
var ip = ipAddress.ToString();
|
||||
var networkUrl = CreateConnectionAddress(ip, port, false);
|
||||
var serviceHost = CreateServiceHost(networkUrl, false);
|
||||
if (serviceHost != null)
|
||||
{
|
||||
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
string ip = ipAddress.ToString();
|
||||
string networkUrl = CreateConnectionAddress(ip, port, false);
|
||||
ServiceHost serviceHost = CreateServiceHost(networkUrl, false);
|
||||
if (serviceHost != null)
|
||||
{
|
||||
_hosts.Add(serviceHost);
|
||||
}
|
||||
}
|
||||
_hosts.Add(serviceHost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count = _hosts.Count;
|
||||
}
|
||||
|
||||
Log.DebugFormat("InitHosts: end. Host's count = {0}", count);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private ServiceHost CreateServiceHost(string serverUrlAdress, bool local)
|
||||
{
|
||||
ServiceHost serviceHost = null;
|
||||
if (serverUrlAdress != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
serviceHost = new ServiceHost(_service);
|
||||
var binding = CreateConnectionBinding(local);
|
||||
Log.DebugFormat("CreateServiceHost: begin. serverUrlAdress = {0}; local = {1}", serverUrlAdress, local);
|
||||
|
||||
serviceHost.AddServiceEndpoint(typeof(IMtApi), binding, serverUrlAdress);
|
||||
serviceHost.Open();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Debug.WriteLine("CreateServiceHost: Create ServiceHost failed. " + e.Message);
|
||||
}
|
||||
if (serverUrlAdress == null)
|
||||
{
|
||||
Log.Warn("CreateServiceHost: end. serverUrlAdress is not defined");
|
||||
return null;
|
||||
}
|
||||
|
||||
ServiceHost serviceHost;
|
||||
try
|
||||
{
|
||||
serviceHost = new ServiceHost(_service);
|
||||
var binding = CreateConnectionBinding(local);
|
||||
|
||||
serviceHost.AddServiceEndpoint(typeof(IMtApi), binding, serverUrlAdress);
|
||||
serviceHost.Open();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Log.ErrorFormat("CreateServiceHost: Error! {0}", e.Message);
|
||||
serviceHost = null;
|
||||
}
|
||||
|
||||
Log.Debug("CreateServiceHost: end.");
|
||||
|
||||
return serviceHost;
|
||||
}
|
||||
|
||||
public void AddExpert(MtExpert expert)
|
||||
{
|
||||
if (expert != null)
|
||||
Log.DebugFormat("AddExpert: begin. expert {0}", expert);
|
||||
|
||||
if (expert == null)
|
||||
{
|
||||
expert.Deinited += expert_Deinited;
|
||||
expert.QuoteChanged += expert_QuoteChanged;
|
||||
expert.OnMtEvent += Expert_OnMtEvent;
|
||||
|
||||
lock (_experts)
|
||||
{
|
||||
_experts.Add(expert);
|
||||
}
|
||||
|
||||
_executorManager.AddCommandExecutor(expert);
|
||||
|
||||
_service.OnQuoteAdded(expert.Quote);
|
||||
Log.Warn("AddExpert: end. expert is not defined");
|
||||
return;
|
||||
}
|
||||
|
||||
expert.Deinited += expert_Deinited;
|
||||
expert.QuoteChanged += expert_QuoteChanged;
|
||||
expert.OnMtEvent += Expert_OnMtEvent;
|
||||
|
||||
lock (_experts)
|
||||
{
|
||||
_experts.Add(expert);
|
||||
}
|
||||
|
||||
_executorManager.AddCommandExecutor(expert);
|
||||
|
||||
_service.OnQuoteAdded(expert.Quote);
|
||||
|
||||
Log.Debug("AddExpert: end.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -126,25 +162,30 @@ namespace MTApiService
|
||||
|
||||
public MtResponse SendCommand(MtCommand command)
|
||||
{
|
||||
MtResponse response = null;
|
||||
Log.DebugFormat("SendCommand: begin. command {0}", command);
|
||||
|
||||
if (command != null)
|
||||
if (command == null)
|
||||
{
|
||||
var task = new MtCommandTask(command);
|
||||
_executorManager.EnqueueCommandTask(task);
|
||||
|
||||
//wait for execute command in MetaTrader
|
||||
response = task.WaitResult(WAIT_RESPONSE_TIME);
|
||||
Log.Warn("SendCommand: end. command is not defined");
|
||||
return null;
|
||||
}
|
||||
|
||||
var task = new MtCommandTask(command);
|
||||
_executorManager.EnqueueCommandTask(task);
|
||||
|
||||
//wait for execute command in MetaTrader
|
||||
var response = task.WaitResult(WaitResponseTime);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
public List<MtQuote> GetQuotes()
|
||||
{
|
||||
Log.Debug("GetQuotes: called");
|
||||
|
||||
lock (_experts)
|
||||
{
|
||||
return (from s in _experts select s.Quote);
|
||||
return _experts.Select(s => s.Quote).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,99 +194,127 @@ namespace MTApiService
|
||||
#region Private Methods
|
||||
private void stopTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
var expertsCount = 0;
|
||||
Log.DebugFormat("stopTimer_Elapsed: begin");
|
||||
|
||||
int expertsCount;
|
||||
|
||||
lock (_experts)
|
||||
{
|
||||
expertsCount = _experts.Count();
|
||||
expertsCount = _experts.Count;
|
||||
}
|
||||
|
||||
if (expertsCount == 0)
|
||||
{
|
||||
_service.OnStopServer();
|
||||
|
||||
Log.DebugFormat("stopTimer_Elapsed: experts count is 0. Call Stop().");
|
||||
|
||||
Stop();
|
||||
}
|
||||
|
||||
var stopTimer = sender as System.Timers.Timer;
|
||||
if (stopTimer != null)
|
||||
{
|
||||
stopTimer.Stop();
|
||||
stopTimer.Elapsed -= stopTimer_Elapsed;
|
||||
}
|
||||
if (stopTimer == null) return;
|
||||
|
||||
stopTimer.Stop();
|
||||
stopTimer.Elapsed -= stopTimer_Elapsed;
|
||||
|
||||
Log.DebugFormat("stopTimer_Elapsed: end");
|
||||
}
|
||||
|
||||
private string CreateConnectionAddress(string host, int port, bool local)
|
||||
private static string CreateConnectionAddress(string host, int port, bool local)
|
||||
{
|
||||
Log.DebugFormat("CreateConnectionAddress: begin. host = {0}, port = {1}, local = {2}", host, port, local);
|
||||
|
||||
string connectionAddress = null;
|
||||
|
||||
if (local == true)
|
||||
if (local)
|
||||
{
|
||||
//by Pipe
|
||||
connectionAddress = "net.pipe://localhost/MtApiService_" + port.ToString();
|
||||
connectionAddress = "net.pipe://localhost/MtApiService_" + port;
|
||||
}
|
||||
else
|
||||
{
|
||||
//by Socket
|
||||
if (host != null)
|
||||
{
|
||||
connectionAddress = "net.tcp://" + host.ToString() + ":" + port.ToString() + "/MtApiService";
|
||||
}
|
||||
connectionAddress = "net.tcp://" + host + ":" + port + "/MtApiService";
|
||||
}
|
||||
}
|
||||
|
||||
Log.DebugFormat("CreateConnectionAddress: end. connectionAddress = {0}", connectionAddress);
|
||||
|
||||
return connectionAddress;
|
||||
}
|
||||
|
||||
private static Binding CreateConnectionBinding(bool local)
|
||||
{
|
||||
Binding connectionBinding = null;
|
||||
Log.DebugFormat("CreateConnectionBinding: begin. local = {0}", local);
|
||||
|
||||
if (local == true)
|
||||
Binding connectionBinding;
|
||||
|
||||
if (local)
|
||||
{
|
||||
//by Pipe
|
||||
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
|
||||
bind.MaxReceivedMessageSize = 2147483647;
|
||||
bind.MaxBufferSize = 2147483647;
|
||||
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
|
||||
{
|
||||
MaxReceivedMessageSize = 2147483647,
|
||||
MaxBufferSize = 2147483647,
|
||||
MaxBufferPoolSize = 2147483647,
|
||||
ReaderQuotas =
|
||||
{
|
||||
MaxArrayLength = 2147483647,
|
||||
MaxBytesPerRead = 2147483647,
|
||||
MaxDepth = 2147483647,
|
||||
MaxStringContentLength = 2147483647,
|
||||
MaxNameTableCharCount = 2147483647
|
||||
}
|
||||
};
|
||||
|
||||
// Commented next statement since it is not required
|
||||
bind.MaxBufferPoolSize = 2147483647;
|
||||
bind.ReaderQuotas.MaxArrayLength = 2147483647;
|
||||
bind.ReaderQuotas.MaxBytesPerRead = 2147483647;
|
||||
bind.ReaderQuotas.MaxDepth = 2147483647;
|
||||
bind.ReaderQuotas.MaxStringContentLength = 2147483647;
|
||||
bind.ReaderQuotas.MaxNameTableCharCount = 2147483647;
|
||||
|
||||
connectionBinding = bind;
|
||||
}
|
||||
else
|
||||
{
|
||||
//by Socket
|
||||
var bind = new NetTcpBinding(SecurityMode.None);
|
||||
bind.MaxReceivedMessageSize = 2147483647;
|
||||
bind.MaxBufferSize = 2147483647;
|
||||
var bind = new NetTcpBinding(SecurityMode.None)
|
||||
{
|
||||
MaxReceivedMessageSize = 2147483647,
|
||||
MaxBufferSize = 2147483647,
|
||||
MaxBufferPoolSize = 2147483647,
|
||||
ReaderQuotas =
|
||||
{
|
||||
MaxArrayLength = 2147483647,
|
||||
MaxBytesPerRead = 2147483647,
|
||||
MaxDepth = 2147483647,
|
||||
MaxStringContentLength = 2147483647,
|
||||
MaxNameTableCharCount = 2147483647
|
||||
}
|
||||
};
|
||||
|
||||
// Commented next statement since it is not required
|
||||
bind.MaxBufferPoolSize = 2147483647;
|
||||
bind.ReaderQuotas.MaxArrayLength = 2147483647;
|
||||
bind.ReaderQuotas.MaxBytesPerRead = 2147483647;
|
||||
bind.ReaderQuotas.MaxDepth = 2147483647;
|
||||
bind.ReaderQuotas.MaxStringContentLength = 2147483647;
|
||||
bind.ReaderQuotas.MaxNameTableCharCount = 2147483647;
|
||||
|
||||
connectionBinding = bind;
|
||||
}
|
||||
|
||||
Log.Debug("CreateConnectionBinding: end.");
|
||||
|
||||
return connectionBinding;
|
||||
}
|
||||
|
||||
private void Stop()
|
||||
{
|
||||
Log.Debug("Stop: begin.");
|
||||
|
||||
_executorManager.Stop();
|
||||
|
||||
lock (_hosts)
|
||||
{
|
||||
if (_hosts.Count == 0)
|
||||
{
|
||||
Log.Debug("Stop: end. Host count is 0.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@@ -254,15 +323,18 @@ namespace MTApiService
|
||||
host.Close();
|
||||
}
|
||||
}
|
||||
catch (TimeoutException)
|
||||
catch (TimeoutException ex)
|
||||
{
|
||||
Log.ErrorFormat("Stop: TimeoutException - {0}", ex.Message);
|
||||
|
||||
foreach (var host in _hosts)
|
||||
{
|
||||
host.Abort();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.ErrorFormat("Stop: Exception - {0}", ex.Message);
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
@@ -272,20 +344,27 @@ namespace MTApiService
|
||||
}
|
||||
|
||||
FireOnStopped();
|
||||
|
||||
Log.Debug("Stop: end.");
|
||||
}
|
||||
|
||||
private void expert_Deinited(object sender, EventArgs e)
|
||||
{
|
||||
if (sender == null)
|
||||
return;
|
||||
Log.Debug("expert_Deinited: begin.");
|
||||
|
||||
var expert = (MtExpert)sender;
|
||||
var expertsCount = 0;
|
||||
var expert = sender as MtExpert;
|
||||
if (expert == null)
|
||||
{
|
||||
Log.Warn("expert_Deinited: end. Expert is not defined.");
|
||||
return;
|
||||
}
|
||||
|
||||
int expertsCount;
|
||||
|
||||
lock (_experts)
|
||||
{
|
||||
_experts.Remove(expert);
|
||||
expertsCount = _experts.Count();
|
||||
expertsCount = _experts.Count;
|
||||
}
|
||||
|
||||
_executorManager.RemoveCommandExecutor(expert);
|
||||
@@ -299,19 +378,29 @@ namespace MTApiService
|
||||
{
|
||||
var stopTimer = new System.Timers.Timer();
|
||||
stopTimer.Elapsed += stopTimer_Elapsed;
|
||||
stopTimer.Interval = STOP_EXPERT_INTERVAL;
|
||||
stopTimer.Interval = StopExpertInterval;
|
||||
stopTimer.Start();
|
||||
}
|
||||
|
||||
Log.Debug("expert_Deinited: end.");
|
||||
}
|
||||
|
||||
private void expert_QuoteChanged(MtExpert expert, MtQuote quote)
|
||||
{
|
||||
Log.DebugFormat("expert_QuoteChanged: begin. expert = {0}, quote = {1}", expert, quote);
|
||||
|
||||
_service.QuoteUpdate(quote);
|
||||
|
||||
Log.Debug("expert_QuoteChanged: end.");
|
||||
}
|
||||
|
||||
private void Expert_OnMtEvent(object sender, MtEventArgs e)
|
||||
{
|
||||
Log.DebugFormat("Expert_OnMtEvent: begin. event = {0}", e.Event);
|
||||
|
||||
_service.OnMtEvent(e.Event);
|
||||
|
||||
Log.Debug("Expert_OnMtEvent: end.");
|
||||
}
|
||||
|
||||
private void FireOnStopped()
|
||||
@@ -328,16 +417,13 @@ namespace MTApiService
|
||||
#region IDispose
|
||||
public void Dispose()
|
||||
{
|
||||
Log.Debug("Dispose: begin");
|
||||
|
||||
Stop();
|
||||
|
||||
Log.Debug("Dispose: end.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private readonly MtService _service;
|
||||
private readonly List<ServiceHost> _hosts = new List<ServiceHost>();
|
||||
private readonly MtCommandExecutorManager _executorManager = new MtCommandExecutorManager();
|
||||
private readonly List<MtExpert> _experts = new List<MtExpert>();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ServiceModel;
|
||||
using System.Net;
|
||||
using System.Diagnostics;
|
||||
using log4net;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public class MtServerInstance
|
||||
{
|
||||
#region Init_Instance
|
||||
#region Fields
|
||||
private const string LogProfileName = "MtApiService";
|
||||
|
||||
static readonly MtServerInstance mInstance = new MtServerInstance();
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtServerInstance));
|
||||
private static readonly MtServerInstance Instance = new MtServerInstance();
|
||||
|
||||
private readonly Dictionary<int, MtServer> _servers = new Dictionary<int, MtServer>();
|
||||
private readonly Dictionary<int, MtExpert> _experts = new Dictionary<int, MtExpert>();
|
||||
#endregion
|
||||
|
||||
#region Init Instance
|
||||
|
||||
private MtServerInstance()
|
||||
{
|
||||
{
|
||||
LogConfigurator.Setup(LogProfileName);
|
||||
}
|
||||
|
||||
static MtServerInstance()
|
||||
{
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
public static MtServerInstance GetInstance()
|
||||
{
|
||||
return mInstance;
|
||||
return Instance;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -33,20 +38,23 @@ namespace MTApiService
|
||||
#region Public Methods
|
||||
public void InitExpert(int expertHandle, int port, string symbol, double bid, double ask, IMetaTraderHandler mtHandler)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::InitExpert: symbol = {0}, expertHandle = {1}, port = {2}", symbol, expertHandle, port);
|
||||
if (mtHandler == null)
|
||||
throw new ArgumentNullException(nameof(mtHandler));
|
||||
|
||||
MtServer server = null;
|
||||
lock (mServersDictionary)
|
||||
Log.InfoFormat("InitExpert: begin. symbol = {0}, expertHandle = {1}, port = {2}", symbol, expertHandle, port);
|
||||
|
||||
MtServer server;
|
||||
lock (_servers)
|
||||
{
|
||||
if (mServersDictionary.ContainsKey(port))
|
||||
if (_servers.ContainsKey(port))
|
||||
{
|
||||
server = mServersDictionary[port];
|
||||
server = _servers[port];
|
||||
}
|
||||
else
|
||||
{
|
||||
server = new MtServer(port);
|
||||
server.Stopped += new EventHandler(server_Stopped);
|
||||
mServersDictionary[port] = server;
|
||||
server.Stopped += server_Stopped;
|
||||
_servers[port] = server;
|
||||
|
||||
server.Start();
|
||||
}
|
||||
@@ -54,137 +62,172 @@ namespace MTApiService
|
||||
|
||||
var expert = new MtExpert(expertHandle, new MtQuote(symbol, bid, ask), mtHandler);
|
||||
|
||||
lock (mExpertsDictionary)
|
||||
lock (_experts)
|
||||
{
|
||||
mExpertsDictionary[expert.Handle] = expert;
|
||||
_experts[expert.Handle] = expert;
|
||||
}
|
||||
|
||||
server.AddExpert(expert);
|
||||
|
||||
Log.Info("InitExpert: end");
|
||||
}
|
||||
|
||||
public void DeinitExpert(int expertHandle)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::DeinitExpert: expertHandle = {0}", expertHandle);
|
||||
Log.InfoFormat("DeinitExpert: begin. symbol = {0}", expertHandle);
|
||||
|
||||
MtExpert expert = null;
|
||||
|
||||
lock (mExpertsDictionary)
|
||||
lock (_experts)
|
||||
{
|
||||
if (mExpertsDictionary.ContainsKey(expertHandle) == true)
|
||||
if (_experts.ContainsKey(expertHandle))
|
||||
{
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
mExpertsDictionary.Remove(expertHandle);
|
||||
expert = _experts[expertHandle];
|
||||
_experts.Remove(expertHandle);
|
||||
}
|
||||
}
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.Deinit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.WarnFormat("DeinitExpert: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
Log.Info("DeinitExpert: end");
|
||||
}
|
||||
|
||||
public void SendQuote(int expertHandle, string symbol, double bid, double ask)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::SendQuote: enter. symbol = {0}, bid = {1}, ask = {2}", symbol, bid, ask);
|
||||
Log.DebugFormat("SendQuote: begin. symbol = {0}, bid = {1}, ask = {2}", symbol, bid, ask);
|
||||
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
MtExpert expert;
|
||||
lock (_experts)
|
||||
{
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
expert = _experts[expertHandle];
|
||||
}
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.Quote = new MtQuote(symbol, bid, ask);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.WarnFormat("SendQuote: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
Debug.WriteLine("MtApiServerInstance::SendQuote: finish.");
|
||||
Log.Debug("SendQuote: end");
|
||||
}
|
||||
|
||||
public void SendEvent(int expertHandle, int eventType, string payload)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::SendEvent called. eventType = {0}, payload = {1}", eventType, payload);
|
||||
Log.DebugFormat("SendEvent: begin. eventType = {0}, payload = {1}", eventType, payload);
|
||||
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
MtExpert expert;
|
||||
lock (_experts)
|
||||
{
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
expert = _experts[expertHandle];
|
||||
}
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.SendEvent(new MtEvent(eventType, payload));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.WarnFormat("SendEvent: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
Debug.WriteLine("MtApiServerInstance::SendEvent: finished");
|
||||
Log.Debug("SendEvent: end");
|
||||
}
|
||||
|
||||
public void SendResponse(int expertHandle, MtResponse response)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::SendResponse: id = {0}, response = {1}", expertHandle, response);
|
||||
Log.DebugFormat("SendResponse: begin. id = {0}, response = {1}", expertHandle, response);
|
||||
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
MtExpert expert;
|
||||
lock (_experts)
|
||||
{
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
expert = _experts[expertHandle];
|
||||
}
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.SendResponse(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.WarnFormat("SendResponse: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
Debug.WriteLine("MtApiServerInstance::SendResponse: finish");
|
||||
Log.Debug("SendResponse: end");
|
||||
}
|
||||
|
||||
public int GetCommandType(int expertHandle)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::GetCommandType: expertHandle = {0}", expertHandle);
|
||||
Log.DebugFormat("GetCommandType: begin. expertHandle = {0}", expertHandle);
|
||||
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
MtExpert expert;
|
||||
lock (_experts)
|
||||
{
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
expert = _experts[expertHandle];
|
||||
}
|
||||
|
||||
return (expert != null) ? expert.GetCommandType() : 0;
|
||||
if (expert == null)
|
||||
{
|
||||
Log.WarnFormat("GetCommandType: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
var retval = expert?.GetCommandType() ?? 0;
|
||||
|
||||
Log.DebugFormat("GetCommandType: end. retval = {0}", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
public object GetCommandParameter(int expertHandle, int index)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::GetCommandParameter: expertHandle = {0}, index = {1}", expertHandle, index);
|
||||
Log.DebugFormat("GetCommandParameter: begin. expertHandle = {0}, index = {1}", expertHandle, index);
|
||||
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
MtExpert expert;
|
||||
lock (_experts)
|
||||
{
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
expert = _experts[expertHandle];
|
||||
}
|
||||
|
||||
return (expert != null) ? expert.GetCommandParameter(index) : null;
|
||||
if (expert == null)
|
||||
{
|
||||
Log.WarnFormat("GetCommandParameter: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
var retval = expert?.GetCommandParameter(index);
|
||||
|
||||
Log.DebugFormat("GetCommandParameter: end. retval = {0}", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private void server_Stopped(object sender, EventArgs e)
|
||||
{
|
||||
MtServer server = (MtServer)sender;
|
||||
var server = (MtServer)sender;
|
||||
server.Stopped -= server_Stopped;
|
||||
|
||||
var port = server.Port;
|
||||
lock (mServersDictionary)
|
||||
|
||||
Log.InfoFormat("server_Stopped: port = {0}", port);
|
||||
|
||||
lock (_servers)
|
||||
{
|
||||
if (mServersDictionary.ContainsKey(port))
|
||||
if (_servers.ContainsKey(port))
|
||||
{
|
||||
mServersDictionary.Remove(port);
|
||||
_servers.Remove(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private readonly MtRegistryManager mConnectionManager = new MtRegistryManager();
|
||||
private readonly Dictionary<int, MtServer> mServersDictionary = new Dictionary<int, MtServer>();
|
||||
private readonly Dictionary<int, MtExpert> mExpertsDictionary = new Dictionary<int, MtExpert>();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
+96
-45
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ServiceModel;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
@@ -18,7 +19,7 @@ namespace MTApiService
|
||||
MtResponse SendCommand(MtCommand command);
|
||||
|
||||
[OperationContract]
|
||||
IEnumerable<MtQuote> GetQuotes();
|
||||
List<MtQuote> GetQuotes();
|
||||
}
|
||||
|
||||
[ServiceContract]
|
||||
@@ -46,107 +47,149 @@ namespace MTApiService
|
||||
InstanceContextMode = InstanceContextMode.Single)]
|
||||
public sealed class MtService : IMtApi
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtService));
|
||||
|
||||
public MtService(IMtApiServer serverCallback)
|
||||
{
|
||||
if (serverCallback == null)
|
||||
throw new ArgumentNullException("serverCallback");
|
||||
throw new ArgumentNullException(nameof(serverCallback));
|
||||
|
||||
mServer = serverCallback;
|
||||
_server = serverCallback;
|
||||
}
|
||||
|
||||
#region IMtApi
|
||||
public bool Connect()
|
||||
{
|
||||
bool connected = false;
|
||||
Log.Debug("Connect: begin");
|
||||
|
||||
IMtApiCallback callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
||||
var callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
||||
|
||||
if (callback != null)
|
||||
if (callback == null)
|
||||
{
|
||||
Log.Warn("Connect: end. Callback is not definded.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var connected = false;
|
||||
|
||||
try
|
||||
{
|
||||
_clientsLocker.AcquireWriterLock(10000);
|
||||
|
||||
try
|
||||
{
|
||||
mClientsLocker.AcquireWriterLock(10000);
|
||||
if (_clientCallbacks.Contains(callback) == false)
|
||||
_clientCallbacks.Add(callback);
|
||||
|
||||
try
|
||||
{
|
||||
if (mClientCallbacks.Contains(callback) == false)
|
||||
mClientCallbacks.Add(callback);
|
||||
|
||||
connected = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseWriterLock();
|
||||
}
|
||||
connected = true;
|
||||
}
|
||||
catch (ApplicationException)
|
||||
finally
|
||||
{
|
||||
_clientsLocker.ReleaseWriterLock();
|
||||
}
|
||||
}
|
||||
catch (ApplicationException ex)
|
||||
{
|
||||
Log.ErrorFormat("Connect: ApplicationException - {0}", ex.Message);
|
||||
}
|
||||
|
||||
Log.DebugFormat("Connect: end. connected = {0}", connected);
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
IMtApiCallback callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
||||
Log.Debug("Disconnect: begin");
|
||||
|
||||
if (callback != null)
|
||||
var callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
||||
|
||||
if (callback == null)
|
||||
{
|
||||
Log.Warn("Disconnect: end. Callback is not definded.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_clientsLocker.AcquireWriterLock(10000);
|
||||
|
||||
try
|
||||
{
|
||||
mClientsLocker.AcquireWriterLock(10000);
|
||||
|
||||
try
|
||||
{
|
||||
mClientCallbacks.Remove(callback);
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseWriterLock();
|
||||
}
|
||||
_clientCallbacks.Remove(callback);
|
||||
}
|
||||
catch (ApplicationException)
|
||||
finally
|
||||
{
|
||||
_clientsLocker.ReleaseWriterLock();
|
||||
}
|
||||
}
|
||||
catch (ApplicationException ex)
|
||||
{
|
||||
Log.ErrorFormat("Disconnect: ApplicationException - {0}", ex.Message);
|
||||
}
|
||||
|
||||
Log.Debug("Disconnect: end.");
|
||||
}
|
||||
|
||||
public MtResponse SendCommand(MtCommand command)
|
||||
{
|
||||
return mServer.SendCommand(command);
|
||||
Log.DebugFormat("SendCommand: called. command = {0}", command);
|
||||
|
||||
return _server.SendCommand(command);
|
||||
}
|
||||
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
public List<MtQuote> GetQuotes()
|
||||
{
|
||||
return mServer.GetQuotes();
|
||||
Log.Debug("GetQuotes: called.");
|
||||
|
||||
return _server.GetQuotes();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void OnStopServer()
|
||||
{
|
||||
Log.Debug("OnStopServer: begin.");
|
||||
|
||||
ExecuteCallbackAction(a => a.OnServerStopped());
|
||||
|
||||
Log.Debug("OnStopServer: end.");
|
||||
}
|
||||
|
||||
public void QuoteUpdate(MtQuote quote)
|
||||
{
|
||||
Log.Debug("QuoteUpdate: begin.");
|
||||
|
||||
ExecuteCallbackAction(a => a.OnQuoteUpdate(quote));
|
||||
|
||||
Log.Debug("QuoteUpdate: end.");
|
||||
}
|
||||
|
||||
public void OnQuoteAdded(MtQuote quote)
|
||||
{
|
||||
Log.Debug("OnQuoteAdded: begin.");
|
||||
|
||||
ExecuteCallbackAction(a => a.OnQuoteAdded(quote));
|
||||
|
||||
Log.Debug("OnQuoteAdded: end.");
|
||||
}
|
||||
|
||||
public void OnQuoteRemoved(MtQuote quote)
|
||||
{
|
||||
Log.Debug("OnQuoteRemoved: begin.");
|
||||
|
||||
ExecuteCallbackAction(a => a.OnQuoteRemoved(quote));
|
||||
|
||||
Log.Debug("OnQuoteRemoved: end.");
|
||||
}
|
||||
|
||||
public void OnMtEvent(MtEvent mtEvent)
|
||||
{
|
||||
Log.Debug("OnMtEvent: begin.");
|
||||
|
||||
ExecuteCallbackAction(a => a.OnMtEvent(mtEvent));
|
||||
|
||||
Log.Debug("OnMtEvent: end.");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -154,22 +197,26 @@ namespace MTApiService
|
||||
|
||||
private void ExecuteCallbackAction(Action<IMtApiCallback> action)
|
||||
{
|
||||
Log.Debug("ExecuteCallbackAction: begin.");
|
||||
|
||||
try
|
||||
{
|
||||
mClientsLocker.AcquireReaderLock(2000);
|
||||
_clientsLocker.AcquireReaderLock(2000);
|
||||
|
||||
List<IMtApiCallback> crashedClientCallbacks = null;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var callback in mClientCallbacks)
|
||||
foreach (var callback in _clientCallbacks)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(callback);
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.ErrorFormat("ExecuteCallbackAction: Exception - {0}", ex.Message);
|
||||
|
||||
if (crashedClientCallbacks == null)
|
||||
crashedClientCallbacks = new List<IMtApiCallback>();
|
||||
|
||||
@@ -179,29 +226,33 @@ namespace MTApiService
|
||||
|
||||
if (crashedClientCallbacks != null)
|
||||
{
|
||||
Log.WarnFormat("ExecuteCallbackAction: crashed callback count = {0}", crashedClientCallbacks.Count);
|
||||
|
||||
foreach (var crashedCallback in crashedClientCallbacks)
|
||||
{
|
||||
mClientCallbacks.Remove(crashedCallback);
|
||||
_clientCallbacks.Remove(crashedCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseReaderLock();
|
||||
_clientsLocker.ReleaseReaderLock();
|
||||
}
|
||||
}
|
||||
catch (ApplicationException)
|
||||
catch (ApplicationException ex)
|
||||
{
|
||||
//TODO: add logging
|
||||
Log.ErrorFormat("ExecuteCallbackAction: ApplicationException - {0}", ex.Message);
|
||||
}
|
||||
|
||||
Log.Debug("ExecuteCallbackAction: end.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private readonly IMtApiServer mServer;
|
||||
private readonly List<IMtApiCallback> mClientCallbacks = new List<IMtApiCallback>();
|
||||
private readonly ReaderWriterLock mClientsLocker = new ReaderWriterLock();
|
||||
private readonly IMtApiServer _server;
|
||||
private readonly List<IMtApiCallback> _clientCallbacks = new List<IMtApiCallback>();
|
||||
private readonly ReaderWriterLock _clientsLocker = new ReaderWriterLock();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="ILMerge" version="2.13.0307" targetFramework="net40" />
|
||||
<package id="log4net" version="2.0.5" targetFramework="net40" />
|
||||
<package id="MSBuild.ILMerge.Task" version="1.0.5" targetFramework="net40" />
|
||||
</packages>
|
||||
@@ -22,6 +22,8 @@ namespace MtApi
|
||||
//Special constant
|
||||
public const int NULL = 0;
|
||||
public const int EMPTY = -1;
|
||||
|
||||
private const string LogProfileName = "MtApiClient";
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
@@ -34,6 +36,8 @@ namespace MtApi
|
||||
|
||||
public MtApiClient()
|
||||
{
|
||||
LogConfigurator.Setup(LogProfileName);
|
||||
|
||||
_client.QuoteAdded += _client_QuoteAdded;
|
||||
_client.QuoteRemoved += _client_QuoteRemoved;
|
||||
_client.QuoteUpdated += _client_QuoteUpdated;
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace MtApi5
|
||||
#endregion
|
||||
|
||||
private const char ParamSeparator = ';';
|
||||
private const string LogProfileName = "MtApi5Client";
|
||||
|
||||
public delegate void QuoteHandler(object sender, string symbol, double bid, double ask);
|
||||
|
||||
@@ -34,6 +35,8 @@ namespace MtApi5
|
||||
#region Public Methods
|
||||
public MtApi5Client()
|
||||
{
|
||||
LogConfigurator.Setup(LogProfileName);
|
||||
|
||||
ConnectionState = Mt5ConnectionState.Disconnected;
|
||||
|
||||
_client.QuoteAdded += mClient_QuoteAdded;
|
||||
@@ -1492,7 +1495,7 @@ namespace MtApi5
|
||||
throw new Exception(ex.Message, ex);
|
||||
}
|
||||
|
||||
var responseValue = response.GetValue();
|
||||
var responseValue = response?.GetValue();
|
||||
return responseValue != null ? (T) responseValue : default(T);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
@@ -10,8 +10,9 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MtApi5TestClient</RootNamespace>
|
||||
<AssemblyName>MtApi5TestClient</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>
|
||||
</TargetFrameworkProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
@@ -25,6 +26,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
@@ -34,6 +36,7 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -50,6 +53,7 @@
|
||||
<CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
|
||||
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
|
||||
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
@@ -67,6 +71,7 @@
|
||||
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
|
||||
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
|
||||
<CodeAnalysisFailOnMissingRules>false</CodeAnalysisFailOnMissingRules>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
@@ -124,6 +129,7 @@
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<None Include="app.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
|
||||
+18
-26
@@ -1,17 +1,17 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18034
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MtApi5TestClient.Properties
|
||||
{
|
||||
|
||||
|
||||
namespace MtApi5TestClient.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
@@ -22,48 +22,40 @@ namespace MtApi5TestClient.Properties
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources
|
||||
{
|
||||
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources()
|
||||
{
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MtApi5TestClient.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set
|
||||
{
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-14
@@ -1,28 +1,24 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18034
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MtApi5TestClient.Properties
|
||||
{
|
||||
|
||||
|
||||
namespace MtApi5TestClient.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/></startup></configuration>
|
||||
Reference in New Issue
Block a user