mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-09 17:01:02 +00:00
Added projects MtApi4 and MtApi5
This commit is contained in:
Executable
+15
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public interface ICommandManager
|
||||
{
|
||||
void EnqueueCommand(MtCommand command);
|
||||
MtCommand DequeueCommand();
|
||||
|
||||
void OnCommandExecuted(MtExpert expert, MtCommand command, MtResponse response);
|
||||
}
|
||||
}
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ServiceModel;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
sealed class DisposableChannel<T> : IDisposable
|
||||
{
|
||||
T proxy;
|
||||
bool disposed;
|
||||
|
||||
public DisposableChannel(T proxy)
|
||||
{
|
||||
if (!(proxy is ICommunicationObject)) throw new ArgumentException("object of type ICommunicationObject expected", "proxy");
|
||||
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
public T Service
|
||||
{
|
||||
get
|
||||
{
|
||||
if (disposed) throw new ObjectDisposedException("DisposableProxy");
|
||||
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (proxy != null)
|
||||
{
|
||||
ICommunicationObject ico = null;
|
||||
|
||||
if (proxy is ICommunicationObject)
|
||||
ico = (ICommunicationObject)proxy;
|
||||
|
||||
// This state may change after the test and there's no known way to synchronize
|
||||
// so that's why we just give it our best shot
|
||||
if (ico.State == CommunicationState.Faulted)
|
||||
ico.Abort(); // Known to be faulted
|
||||
else
|
||||
try
|
||||
{
|
||||
ico.Close(); // Attempt to close, this is the nice way and we ought to be nice
|
||||
}
|
||||
catch
|
||||
{
|
||||
ico.Abort(); // Sometimes being nice isn't an option
|
||||
}
|
||||
|
||||
proxy = default(T);
|
||||
}
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public interface IMetaTraderHandler
|
||||
{
|
||||
void SendTickToMetaTrader(int handle);
|
||||
}
|
||||
}
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public interface IMtApiServer
|
||||
{
|
||||
MtResponse SendCommand(MtCommand command);
|
||||
IEnumerable<MtQuote> GetQuotes();
|
||||
}
|
||||
}
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{DE76D5C7-B99C-4467-8408-78173BDD84E0}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MTApiService</RootNamespace>
|
||||
<AssemblyName>MTApiService</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile>
|
||||
</TargetFrameworkProfile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>
|
||||
</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>MetaTraderApiKey.pfx</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ICommandManager.cs" />
|
||||
<Compile Include="IMetaTraderHandler.cs" />
|
||||
<Compile Include="MtCommandEventArgs.cs" />
|
||||
<Compile Include="IDisposableChannel.cs" />
|
||||
<Compile Include="IMtApiServer.cs" />
|
||||
<Compile Include="MtApiProxy.cs" />
|
||||
<Compile Include="MtClient.cs" />
|
||||
<Compile Include="MtMqlBookInfo.cs" />
|
||||
<Compile Include="MtMqlRates.cs" />
|
||||
<Compile Include="MtMqlTick.cs" />
|
||||
<Compile Include="MtMqlTradeRequest.cs" />
|
||||
<Compile Include="MtRegistryManager.cs" />
|
||||
<Compile Include="MtConnectionProfile.cs" />
|
||||
<Compile Include="MtExecutorManager.cs" />
|
||||
<Compile Include="MtExpert.cs" />
|
||||
<Compile Include="MtInstrument.cs" />
|
||||
<Compile Include="MtResponse.cs" />
|
||||
<Compile Include="MtServer.cs" />
|
||||
<Compile Include="MtCommand.cs" />
|
||||
<Compile Include="MtServerInstance.cs" />
|
||||
<Compile Include="MtService.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="MetaTraderApiKey.pfx" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
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
|
||||
{
|
||||
public MtApiProxy(InstanceContext callbackContext, Binding binding,
|
||||
EndpointAddress remoteAddress)
|
||||
: base(callbackContext, binding, remoteAddress)
|
||||
{
|
||||
base.InnerDuplexChannel.Faulted += new EventHandler(InnerDuplexChannel_Faulted);
|
||||
base.InnerDuplexChannel.Open();
|
||||
}
|
||||
|
||||
#region IMtApi Members
|
||||
|
||||
public bool Connect()
|
||||
{
|
||||
return Channel.Connect();
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
Channel.Disconnect();
|
||||
}
|
||||
|
||||
public MtResponse SendCommand(MtCommand command)
|
||||
{
|
||||
return Channel.SendCommand(command);
|
||||
}
|
||||
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
{
|
||||
return Channel.GetQuotes();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
catch (CommunicationException)
|
||||
{
|
||||
this.Abort();
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
this.Abort();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
this.Abort();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private void InnerDuplexChannel_Faulted(object sender, EventArgs e)
|
||||
{
|
||||
if (Faulted != null)
|
||||
Faulted(this, e);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
public event EventHandler Faulted;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Executable
+305
@@ -0,0 +1,305 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.Collections;
|
||||
using System.ServiceModel;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
[CallbackBehavior(UseSynchronizationContext = false)]
|
||||
public class MtClient: IMtApiCallback, IDisposable
|
||||
{
|
||||
private static string SERVICE_NAME = "MtApiService";
|
||||
|
||||
// public delegate void MtInstrumentsChangedHandler(string addedInstrument, string removedInstrument);
|
||||
public delegate void MtQuoteHandler(MtQuote quote);
|
||||
|
||||
#region Public Methods
|
||||
public void Open(string host, int port)
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::Open");
|
||||
|
||||
if (string.IsNullOrEmpty(host) == true)
|
||||
throw new ArgumentNullException("host", "host is null or epmty");
|
||||
|
||||
if (port < 0 || port > 65536)
|
||||
throw new ArgumentOutOfRangeException("port", "port value is invalid");
|
||||
|
||||
string urlService = string.Format("net.tcp://{0}:{1}/{2}", host, port, SERVICE_NAME);
|
||||
|
||||
lock (mClientLocker)
|
||||
{
|
||||
if (mProxy != null)
|
||||
return;
|
||||
|
||||
var bind = new NetTcpBinding();
|
||||
bind.MaxReceivedMessageSize = 2147483647;
|
||||
bind.MaxBufferSize = 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;
|
||||
|
||||
mProxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
|
||||
mProxy.Faulted += mProxy_Faulted;
|
||||
}
|
||||
}
|
||||
|
||||
public void Open(int port)
|
||||
{
|
||||
if (port < 0 || port > 65536)
|
||||
throw new ArgumentOutOfRangeException("port", "port value is invalid");
|
||||
|
||||
string urlService = "net.pipe://localhost/" + SERVICE_NAME + "_" + port.ToString();
|
||||
|
||||
lock (mClientLocker)
|
||||
{
|
||||
if (mProxy != null)
|
||||
return;
|
||||
|
||||
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
|
||||
bind.MaxReceivedMessageSize = 2147483647;
|
||||
bind.MaxBufferSize = 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;
|
||||
|
||||
mProxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
|
||||
mProxy.Faulted += mProxy_Faulted;
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::Close");
|
||||
|
||||
lock (mClientLocker)
|
||||
{
|
||||
if (mProxy != null)
|
||||
{
|
||||
mProxy.Faulted -= mProxy_Faulted;
|
||||
mProxy.Dispose();
|
||||
mProxy = null;
|
||||
}
|
||||
|
||||
mIsConnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Connect()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::Connect");
|
||||
|
||||
try
|
||||
{
|
||||
lock (mClientLocker)
|
||||
{
|
||||
if (mProxy != null && mIsConnected == true)
|
||||
return;
|
||||
|
||||
mIsConnected = mProxy.Connect();
|
||||
|
||||
if (mIsConnected == false)
|
||||
throw new Exception("Connected failed");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("[ERROR] MtClient::Connect: {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
|
||||
throw new CommunicationException(string.Format("Connection failed to service"));
|
||||
}
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::Disconnect");
|
||||
|
||||
try
|
||||
{
|
||||
lock (mClientLocker)
|
||||
{
|
||||
mIsConnected = false;
|
||||
|
||||
if (mProxy != null)
|
||||
mProxy.Disconnect();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("[ERROR] MtClient::Disconnect: {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
public MtResponse SendCommand(int commandType, ArrayList commandParameters)
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::SendCommand: commandType = {0}", commandType);
|
||||
|
||||
MtResponse result = null;
|
||||
|
||||
try
|
||||
{
|
||||
lock (mClientLocker)
|
||||
{
|
||||
if (mProxy != null && mIsConnected == true)
|
||||
result = mProxy.SendCommand(new MtCommand(commandType, commandParameters));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("[ERROR] MtClient::SendCommand: {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
|
||||
throw new CommunicationException("Service connection failed! " + ex.Message);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::GetQuotes");
|
||||
|
||||
IEnumerable<MtQuote> result = null;
|
||||
|
||||
try
|
||||
{
|
||||
lock (mClientLocker)
|
||||
{
|
||||
if (mProxy != null && mIsConnected == true)
|
||||
result = mProxy.GetQuotes();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("[ERROR] MtClient::GetQuotes: {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
|
||||
throw new CommunicationException("Service connection failed");
|
||||
}
|
||||
|
||||
return result;;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IMtApiCallback Members
|
||||
|
||||
public void OnQuoteUpdate(MtQuote quote)
|
||||
{
|
||||
if (quote != null)
|
||||
{
|
||||
if (QuoteUpdated != null)
|
||||
{
|
||||
QuoteUpdated(quote);
|
||||
}
|
||||
|
||||
Debug.WriteLine("[INFO] MtClient::OnQuoteUpdate: " + quote);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnQuoteAdded(MtQuote quote)
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::OnQuoteAdded");
|
||||
|
||||
if (QuoteAdded != null)
|
||||
{
|
||||
QuoteAdded(quote);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnQuoteRemoved(MtQuote quote)
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::OnQuoteRemoved");
|
||||
|
||||
if (QuoteRemoved != null)
|
||||
{
|
||||
QuoteRemoved(quote);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnServerStopped()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::OnServerStopped");
|
||||
|
||||
Close();
|
||||
|
||||
if (ServerDisconnected != null)
|
||||
{
|
||||
ServerDisconnected(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public bool IsConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (mClientLocker)
|
||||
{
|
||||
return mProxy.State == CommunicationState.Opened && mIsConnected == true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
void mProxy_Faulted(object sender, EventArgs e)
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::mProxy_Faulted");
|
||||
|
||||
Close();
|
||||
|
||||
if (ServerFailed != null)
|
||||
{
|
||||
ServerFailed(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Debug.WriteLine("[INFO] MtClient::Dispose");
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
public event MtQuoteHandler QuoteAdded;
|
||||
public event MtQuoteHandler QuoteRemoved;
|
||||
public event MtQuoteHandler QuoteUpdated;
|
||||
public event EventHandler ServerDisconnected;
|
||||
public event EventHandler ServerFailed;
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private readonly object mClientLocker = new object();
|
||||
private MtApiProxy mProxy = null;
|
||||
private bool mIsConnected = false;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ServiceModel;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Collections;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
[DataContract]
|
||||
public class MtCommand
|
||||
{
|
||||
public MtCommand(int commandType, ArrayList parameters)
|
||||
{
|
||||
CommandType = commandType;
|
||||
Parameters = parameters;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public int CommandType { get; private set; }
|
||||
|
||||
[DataMember]
|
||||
public ArrayList Parameters { get; private set; }
|
||||
|
||||
}
|
||||
}
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public class MtCommandExecuteEventArgs: EventArgs
|
||||
{
|
||||
public MtCommand Command { get; private set; }
|
||||
public MtResponse Response { get; private set; }
|
||||
|
||||
public MtCommandExecuteEventArgs(MtCommand command, MtResponse response)
|
||||
{
|
||||
Command = command;
|
||||
Response = response;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public class MtConnectionProfile
|
||||
{
|
||||
public MtConnectionProfile(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string Host { get; set; }
|
||||
public int Port { get; set; }
|
||||
}
|
||||
}
|
||||
Executable
+132
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
class MtCommandExecutorManager : ICommandManager
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
mCommandExecutors.Clear();
|
||||
mCommands.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddCommandExecutor(MtExpert commandExecutor)
|
||||
{
|
||||
if (commandExecutor == null)
|
||||
return;
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
if (mCommandExecutors.Contains(commandExecutor) == true)
|
||||
return;
|
||||
|
||||
mCommandExecutors.Add(commandExecutor);
|
||||
|
||||
commandExecutor.CommandManager = this;
|
||||
|
||||
if (mCurrentExecutor == null)
|
||||
{
|
||||
mCurrentExecutor = commandExecutor;
|
||||
mCurrentExecutor.IsCommandExecutor = true;
|
||||
|
||||
if (mCommands.Count > 0)
|
||||
{
|
||||
mCurrentExecutor.NotifyCommandReady();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveCommandExecutor(MtExpert commandExecutor)
|
||||
{
|
||||
if (commandExecutor == null)
|
||||
return;
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
if (mCommandExecutors.Contains(commandExecutor) == false)
|
||||
return;
|
||||
|
||||
mCommandExecutors.Remove(commandExecutor);
|
||||
|
||||
if (mCurrentExecutor == commandExecutor)
|
||||
{
|
||||
mCurrentExecutor.IsCommandExecutor = false;
|
||||
mCurrentExecutor = mCommandExecutors.Count > 0 ? mCommandExecutors[0] : null;
|
||||
|
||||
if (mCommands.Count > 0)
|
||||
{
|
||||
mCurrentExecutor.NotifyCommandReady();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EnqueueCommand(MtCommand command)
|
||||
{
|
||||
if (command == null)
|
||||
return;
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
mCommands.Enqueue(command);
|
||||
|
||||
mCurrentExecutor.NotifyCommandReady();
|
||||
}
|
||||
}
|
||||
|
||||
public MtCommand DequeueCommand()
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
return mCommands.Count > 0 ? mCommands.Dequeue() : null;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCommandExecuted(MtExpert expert, MtCommand command, MtResponse response)
|
||||
{
|
||||
if (expert == null)
|
||||
return;
|
||||
|
||||
if (CommandExecuted != null)
|
||||
{
|
||||
CommandExecuted(this, new MtCommandExecuteEventArgs(command, response));
|
||||
}
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
if (expert == mCurrentExecutor)
|
||||
{
|
||||
if (mCommands.Count > 0)
|
||||
{
|
||||
mCurrentExecutor.NotifyCommandReady();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
public event EventHandler<MtCommandExecuteEventArgs> CommandExecuted;
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private MtExpert mCurrentExecutor;
|
||||
|
||||
private List<MtExpert> mCommandExecutors = new List<MtExpert>();
|
||||
private Queue<MtCommand> mCommands = new Queue<MtCommand>();
|
||||
|
||||
private readonly object _locker = new object();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Executable
+157
@@ -0,0 +1,157 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public class MtExpert
|
||||
{
|
||||
public delegate void MtQuoteHandler(MtExpert expert, MtQuote quote);
|
||||
|
||||
#region Properties
|
||||
private MtQuote _Quote;
|
||||
public MtQuote Quote
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
return _Quote;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock(_locker)
|
||||
{
|
||||
_Quote = value;
|
||||
}
|
||||
|
||||
if (QuoteChanged != null)
|
||||
{
|
||||
QuoteChanged(this, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
public int Handle { get; private set; }
|
||||
|
||||
private volatile bool _IsEnable = true;
|
||||
public bool IsEnable
|
||||
{
|
||||
get { return _IsEnable; }
|
||||
private set { _IsEnable = value; }
|
||||
}
|
||||
|
||||
private volatile bool _IsCommandExecutor = true;
|
||||
public bool IsCommandExecutor
|
||||
{
|
||||
get { return _IsCommandExecutor; }
|
||||
set { _IsCommandExecutor = value; }
|
||||
}
|
||||
|
||||
public ICommandManager CommandManager
|
||||
{
|
||||
private get
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
return mCommandManager;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
mCommandManager = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public MtExpert(int handle, MtQuote quote, IMetaTraderHandler mtHandler)
|
||||
{
|
||||
Quote = quote;
|
||||
Handle = handle;
|
||||
mMtHadler = mtHandler;
|
||||
}
|
||||
|
||||
public void Deinit()
|
||||
{
|
||||
IsEnable = false;
|
||||
|
||||
if (Deinited != null)
|
||||
{
|
||||
Deinited(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendResponse(MtResponse response)
|
||||
{
|
||||
MtCommand command = mCommand;
|
||||
mCommand = null;
|
||||
|
||||
ICommandManager commandManager = CommandManager;
|
||||
if (commandManager != null)
|
||||
{
|
||||
commandManager.OnCommandExecuted(this, command, response);
|
||||
}
|
||||
}
|
||||
|
||||
public int GetCommandType()
|
||||
{
|
||||
if (IsCommandExecutor)
|
||||
{
|
||||
ICommandManager commandManager = CommandManager;
|
||||
if (mCommandManager != null)
|
||||
{
|
||||
mCommand = mCommandManager.DequeueCommand();
|
||||
}
|
||||
}
|
||||
|
||||
return mCommand != null ? mCommand.CommandType : 0;
|
||||
}
|
||||
|
||||
public object GetCommandParameter(int index)
|
||||
{
|
||||
if (mCommand != null && mCommand.Parameters != null
|
||||
&& index >= 0 && index < mCommand.Parameters.Count)
|
||||
{
|
||||
return mCommand.Parameters[index];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IMtCommandExecutor
|
||||
public void NotifyCommandReady()
|
||||
{
|
||||
SendTickToMetaTrader();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Private Methods
|
||||
private void SendTickToMetaTrader()
|
||||
{
|
||||
if (mMtHadler != null)
|
||||
{
|
||||
mMtHadler.SendTickToMetaTrader(Handle);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
public event EventHandler Deinited;
|
||||
public event MtQuoteHandler QuoteChanged;
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private readonly IMetaTraderHandler mMtHadler;
|
||||
private MtCommand mCommand;
|
||||
private ICommandManager mCommandManager;
|
||||
private readonly object _locker = new object();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
[DataContract]
|
||||
public class MtQuote
|
||||
{
|
||||
[DataMember]
|
||||
public string Instrument { get; private set; }
|
||||
|
||||
[DataMember]
|
||||
public double Bid { get; private set; }
|
||||
|
||||
[DataMember]
|
||||
public double Ask { get; private set; }
|
||||
|
||||
public MtQuote(string instrument, double bid, double ask)
|
||||
{
|
||||
Instrument = instrument;
|
||||
Bid = bid;
|
||||
Ask = ask;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "Instrument = " + Instrument + ", Bid = " + Bid + ", Ask = " + Ask;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
[DataContract]
|
||||
public class MtMqlBookInfo
|
||||
{
|
||||
[DataMember]
|
||||
public int type { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public double price { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public long volume { get; set; }
|
||||
}
|
||||
}
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
[DataContract]
|
||||
public class MtMqlRates
|
||||
{
|
||||
[DataMember]
|
||||
public long time { get; set; } // Period start time
|
||||
[DataMember]
|
||||
public double open { get; set; } // Open price
|
||||
[DataMember]
|
||||
public double high { get; set; } // The highest price of the period
|
||||
[DataMember]
|
||||
public double low { get; set; } // The lowest price of the period
|
||||
[DataMember]
|
||||
public double close { get; set; } // Close price
|
||||
[DataMember]
|
||||
public long tick_volume { get; set; } // Tick volume
|
||||
[DataMember]
|
||||
public int spread { get; set; } // Spread
|
||||
[DataMember]
|
||||
public long real_volume { get; set; } // Trade volume
|
||||
}
|
||||
}
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
[DataContract]
|
||||
public class MtMqlTick
|
||||
{
|
||||
[DataMember]
|
||||
public long time { get; set; } // Time of the last prices update
|
||||
|
||||
[DataMember]
|
||||
public double bid { get; set; } // Current Bid price
|
||||
|
||||
[DataMember]
|
||||
public double ask { get; set; } // Current Ask price
|
||||
|
||||
[DataMember]
|
||||
public double last { get; set; } // Price of the last deal (Last)
|
||||
|
||||
[DataMember]
|
||||
public ulong volume { get; set; } // Volume for the current Last price
|
||||
}
|
||||
}
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
[DataContract]
|
||||
public class MtMqlTradeRequest
|
||||
{
|
||||
[DataMember]
|
||||
public int Action { get; set; }
|
||||
[DataMember]
|
||||
public uint Magic { get; set; }
|
||||
[DataMember]
|
||||
public uint Order { get; set; }
|
||||
[DataMember]
|
||||
public string Symbol { get; set; }
|
||||
[DataMember]
|
||||
public double Volume { get; set; }
|
||||
[DataMember]
|
||||
public double Price { get; set; }
|
||||
[DataMember]
|
||||
public double Stoplimit { get; set; }
|
||||
[DataMember]
|
||||
public double Sl { get; set; }
|
||||
[DataMember]
|
||||
public double Tp { get; set; }
|
||||
[DataMember]
|
||||
public uint Deviation { get; set; }
|
||||
[DataMember]
|
||||
public int Type { get; set; }
|
||||
[DataMember]
|
||||
public int Type_filling { get; set; }
|
||||
[DataMember]
|
||||
public int Type_time { get; set; }
|
||||
[DataMember]
|
||||
public DateTime Expiration { get; set; }
|
||||
[DataMember]
|
||||
public string Comment { get; set; }
|
||||
}
|
||||
}
|
||||
Executable
+325
@@ -0,0 +1,325 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Win32;
|
||||
using System.Diagnostics;
|
||||
|
||||
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";
|
||||
|
||||
#region Public Methods
|
||||
public static IEnumerable<MtConnectionProfile> LoadConnectionProfiles()
|
||||
{
|
||||
return LoadConnectionProfilesFromRegisty();
|
||||
}
|
||||
|
||||
public static MtConnectionProfile LoadConnectionProfile(string profileName)
|
||||
{
|
||||
return string.IsNullOrEmpty(profileName) == false ? LoadConnectionProfileFromRegisty(profileName) : null;
|
||||
}
|
||||
|
||||
public static void AddConnectionProfile(MtConnectionProfile profile)
|
||||
{
|
||||
if (profile != null && string.IsNullOrEmpty(profile.Name) == false)
|
||||
{
|
||||
SaveConnectionProfileToRegistry(profile);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveConnectionProfile(string profileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(profileName) == false)
|
||||
{
|
||||
DeleteConnectionProfileFromRegistry(profileName);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReadSignatureKey(string accountName, string accountNumber)
|
||||
{
|
||||
if (string.IsNullOrEmpty(accountName)
|
||||
|| string.IsNullOrEmpty(accountNumber))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string signature = null;
|
||||
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
if (softwareRegKey != null)
|
||||
{
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey != null)
|
||||
{
|
||||
using (appRegKey)
|
||||
{
|
||||
var accountKey = appRegKey.OpenSubKey(accountName, true);
|
||||
if (accountKey != null)
|
||||
{
|
||||
using (accountKey)
|
||||
{
|
||||
var numberKey = accountKey.OpenSubKey(accountNumber, true);
|
||||
if (numberKey != null)
|
||||
{
|
||||
using (numberKey)
|
||||
{
|
||||
signature = numberKey.GetValue(SIGNATURE_REGVALUE_NAME).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
public static string SaveSignatureKey(string accountName, string accountNumber, string signature)
|
||||
{
|
||||
if (string.IsNullOrEmpty(accountName)
|
||||
|| string.IsNullOrEmpty(accountNumber))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
RegistryKey softwareRgKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
|
||||
if (softwareRgKey == null)
|
||||
return null;
|
||||
|
||||
string retVal = null;
|
||||
|
||||
using (softwareRgKey)
|
||||
{
|
||||
|
||||
//app name
|
||||
var appRegKey = softwareRgKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey == null)
|
||||
{
|
||||
appRegKey = softwareRgKey.CreateSubKey(APP_NAME);
|
||||
}
|
||||
|
||||
using (appRegKey)
|
||||
{
|
||||
//account name
|
||||
var accountKey = appRegKey.OpenSubKey(accountName, true);
|
||||
if (accountKey == null)
|
||||
{
|
||||
accountKey = appRegKey.CreateSubKey(accountName);
|
||||
}
|
||||
|
||||
using (accountKey)
|
||||
{
|
||||
//account number
|
||||
var numberKey = accountKey.OpenSubKey(accountNumber, true);
|
||||
if (numberKey == null)
|
||||
{
|
||||
numberKey = accountKey.CreateSubKey(accountNumber);
|
||||
}
|
||||
|
||||
using (numberKey)
|
||||
{
|
||||
numberKey.SetValue(SIGNATURE_REGVALUE_NAME, signature);
|
||||
|
||||
retVal = numberKey.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static bool ExportKey(string RegKey, string SavePath)
|
||||
{
|
||||
string path = "\"" + SavePath + "\"";
|
||||
string key = "\"" + RegKey + "\"";
|
||||
|
||||
Process 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();
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (proc != null)
|
||||
proc.Dispose();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private static IEnumerable<MtConnectionProfile> LoadConnectionProfilesFromRegisty()
|
||||
{
|
||||
List<MtConnectionProfile> profiles = null;
|
||||
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
if (softwareRegKey != null)
|
||||
{
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey != null)
|
||||
{
|
||||
using (appRegKey)
|
||||
{
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
if (profilesRegKey != null)
|
||||
{
|
||||
using (profilesRegKey)
|
||||
{
|
||||
profiles = new List<MtConnectionProfile>();
|
||||
|
||||
foreach (string profileNameKey in profilesRegKey.GetSubKeyNames())
|
||||
{
|
||||
using (RegistryKey tempKey = profilesRegKey.OpenSubKey(profileNameKey))
|
||||
{
|
||||
var profile = new MtConnectionProfile(profileNameKey);
|
||||
|
||||
profile.Host = tempKey.GetValue(HOST_REGVALUE_NAME).ToString();
|
||||
profile.Port = (int)tempKey.GetValue(PORT_REGVALUE_NAME);
|
||||
|
||||
profiles.Add(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return profiles;
|
||||
}
|
||||
|
||||
private static MtConnectionProfile LoadConnectionProfileFromRegisty(string profileName)
|
||||
{
|
||||
MtConnectionProfile profile = null;
|
||||
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
if (softwareRegKey != null)
|
||||
{
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey != null)
|
||||
{
|
||||
using (appRegKey)
|
||||
{
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
if (profilesRegKey != null)
|
||||
{
|
||||
using (profilesRegKey)
|
||||
{
|
||||
using (RegistryKey tempKey = profilesRegKey.OpenSubKey(profileName))
|
||||
{
|
||||
profile = new MtConnectionProfile(profileName);
|
||||
|
||||
profile.Host = tempKey.GetValue(HOST_REGVALUE_NAME).ToString();
|
||||
profile.Port = (int)tempKey.GetValue(PORT_REGVALUE_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
private static void SaveConnectionProfileToRegistry(MtConnectionProfile profile)
|
||||
{
|
||||
RegistryKey softwareRgKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
|
||||
if (softwareRgKey == null)
|
||||
return;
|
||||
|
||||
using (softwareRgKey)
|
||||
{
|
||||
//app name
|
||||
var appRegKey = softwareRgKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey == null)
|
||||
{
|
||||
appRegKey = softwareRgKey.CreateSubKey(APP_NAME);
|
||||
}
|
||||
|
||||
using (appRegKey)
|
||||
{
|
||||
//ConnectionProfiles key
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
if (profilesRegKey == null)
|
||||
{
|
||||
profilesRegKey = appRegKey.CreateSubKey(PROFILES_REGKEY);
|
||||
}
|
||||
|
||||
using (profilesRegKey)
|
||||
{
|
||||
var profileKey = profilesRegKey.CreateSubKey(profile.Name);
|
||||
|
||||
using (profileKey)
|
||||
{
|
||||
profileKey.SetValue(HOST_REGVALUE_NAME, profile.Host);
|
||||
profileKey.SetValue(PORT_REGVALUE_NAME, profile.Port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeleteConnectionProfileFromRegistry(string profileName)
|
||||
{
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
if (softwareRegKey == null)
|
||||
return;
|
||||
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey == null)
|
||||
return;
|
||||
|
||||
using (appRegKey)
|
||||
{
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
if (profilesRegKey == null)
|
||||
return;
|
||||
|
||||
using (profilesRegKey)
|
||||
{
|
||||
profilesRegKey.DeleteSubKey(profileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Executable
+182
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Collections;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
[DataContract]
|
||||
[KnownType("GetKnownTypes")]
|
||||
public abstract class MtResponse
|
||||
{
|
||||
static IEnumerable<Type> GetKnownTypes()
|
||||
{
|
||||
return new Type[] { typeof(MtResponseInt), typeof(MtResponseDouble),
|
||||
typeof(MtResponseString), typeof(MtResponseBool),
|
||||
typeof(MtResponseLong), typeof(MtResponseULong),
|
||||
typeof(MtResponseDoubleArray), typeof(MtResponseIntArray),
|
||||
typeof(MtResponseLongArray), typeof(MtResponseMqlTick),
|
||||
typeof(MtResponseArrayList), typeof(MtResponseMqlRatesArray),
|
||||
typeof(MtResponseMqlBookInfoArray)};
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseInt: MtResponse
|
||||
{
|
||||
public MtResponseInt(int value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public int Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseLong : MtResponse
|
||||
{
|
||||
public MtResponseLong(long value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public long Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseULong : MtResponse
|
||||
{
|
||||
public MtResponseULong(ulong value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public ulong Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseDouble : MtResponse
|
||||
{
|
||||
public MtResponseDouble(double value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public double Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseString : MtResponse
|
||||
{
|
||||
public MtResponseString(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseBool : MtResponse
|
||||
{
|
||||
public MtResponseBool(bool value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public bool Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseDoubleArray : MtResponse
|
||||
{
|
||||
public MtResponseDoubleArray(double[] value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public double[] Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseIntArray : MtResponse
|
||||
{
|
||||
public MtResponseIntArray(int[] value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public int[] Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseLongArray : MtResponse
|
||||
{
|
||||
public MtResponseLongArray(long[] value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public long[] Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseArrayList : MtResponse
|
||||
{
|
||||
public MtResponseArrayList(ArrayList value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public ArrayList Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseMqlRatesArray : MtResponse
|
||||
{
|
||||
public MtResponseMqlRatesArray(MtMqlRates[] value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public MtMqlRates[] Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseMqlTick : MtResponse
|
||||
{
|
||||
public MtResponseMqlTick(MtMqlTick value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public MtMqlTick Value { get; private set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class MtResponseMqlBookInfoArray : MtResponse
|
||||
{
|
||||
public MtResponseMqlBookInfoArray(MtMqlBookInfo[] value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public MtMqlBookInfo[] Value { get; private set; }
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+334
@@ -0,0 +1,334 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.ServiceModel;
|
||||
using System.Net;
|
||||
using System.Diagnostics;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
class MtServer : IDisposable, IMtApiServer
|
||||
{
|
||||
#region Constants
|
||||
private const int WAIT_RESPONSE_TIME = 40000; // 40 sec
|
||||
private const int STOP_EXPERT_INTERVAL = 1000; // 1 sec
|
||||
#endregion
|
||||
|
||||
#region ctor
|
||||
public MtServer(MtConnectionProfile profile)
|
||||
{
|
||||
Profile = profile;
|
||||
mService = new MtService(this);
|
||||
|
||||
mExecutorManager = new MtCommandExecutorManager();
|
||||
mExecutorManager.CommandExecuted += mExecutorManager_CommandExecuted;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public MtConnectionProfile Profile { get; private set; }
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void Start()
|
||||
{
|
||||
lock (mHostLocker)
|
||||
{
|
||||
if (mHost != null)
|
||||
return;
|
||||
|
||||
ServiceHost host = new ServiceHost(mService);
|
||||
|
||||
string mServerUrlAdress = CreateConnectionAddress(Profile);
|
||||
Binding mBinding = CreateConnectionBinding(Profile);
|
||||
|
||||
host.AddServiceEndpoint(typeof(IMtApi), mBinding, mServerUrlAdress);
|
||||
host.Open();
|
||||
|
||||
mHost = host;
|
||||
}
|
||||
|
||||
lock (mExpertsLocker)
|
||||
{
|
||||
mExperts = new List<MtExpert>();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddExpert(MtExpert expert)
|
||||
{
|
||||
if (expert != null)
|
||||
{
|
||||
expert.Deinited += new EventHandler(expert_Deinited);
|
||||
expert.QuoteChanged += new MtExpert.MtQuoteHandler(expert_QuoteChanged);
|
||||
|
||||
lock (mExpertsLocker)
|
||||
{
|
||||
mExperts.Add(expert);
|
||||
}
|
||||
|
||||
mExecutorManager.AddCommandExecutor(expert);
|
||||
|
||||
mService.OnQuoteAdded(expert.Quote);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IMtApiServerCallback Members
|
||||
|
||||
public MtResponse SendCommand(MtCommand command)
|
||||
{
|
||||
MtResponse response = null;
|
||||
|
||||
if (command != null)
|
||||
{
|
||||
EventWaitHandle responseWaiter = new AutoResetEvent(false);
|
||||
|
||||
lock (mResponseLocker)
|
||||
{
|
||||
mResponseWaiters[command] = responseWaiter;
|
||||
}
|
||||
|
||||
mExecutorManager.EnqueueCommand(command);
|
||||
|
||||
//wait for execute command in MetaTrader
|
||||
responseWaiter.WaitOne(WAIT_RESPONSE_TIME);
|
||||
|
||||
lock (mResponseLocker)
|
||||
{
|
||||
if (mResponseWaiters.ContainsKey(command) == true)
|
||||
{
|
||||
mResponseWaiters.Remove(command);
|
||||
}
|
||||
|
||||
if (mResponses.ContainsKey(command) == true)
|
||||
{
|
||||
response = mResponses[command];
|
||||
mResponses.Remove(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
{
|
||||
lock (mExpertsLocker)
|
||||
{
|
||||
return (from s in mExperts select s.Quote);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private void stopTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
int expertsCount = 0;
|
||||
|
||||
lock (mExpertsLocker)
|
||||
{
|
||||
expertsCount = mExperts.Count();
|
||||
}
|
||||
|
||||
if (expertsCount == 0)
|
||||
{
|
||||
mService.OnStopServer();
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
var stopTimer = sender as System.Timers.Timer;
|
||||
stopTimer.Stop();
|
||||
stopTimer.Elapsed -= stopTimer_Elapsed;
|
||||
}
|
||||
|
||||
private string CreateConnectionAddress(MtConnectionProfile profile)
|
||||
{
|
||||
string connectionAddress = null;
|
||||
|
||||
if (profile != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(profile.Host))
|
||||
{
|
||||
//by Pipe
|
||||
connectionAddress = "net.pipe://localhost/MtApiService_" + profile.Port.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
//by Socket
|
||||
connectionAddress = "net.tcp://" + profile.Host.ToString() + ":" + profile.Port.ToString() + "/MtApiService";
|
||||
}
|
||||
}
|
||||
|
||||
return connectionAddress;
|
||||
}
|
||||
|
||||
private static Binding CreateConnectionBinding(MtConnectionProfile profile)
|
||||
{
|
||||
Binding connectionBinding = null;
|
||||
|
||||
if (profile != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(profile.Host))
|
||||
{
|
||||
//by Pipe
|
||||
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
|
||||
bind.MaxReceivedMessageSize = 2147483647;
|
||||
bind.MaxBufferSize = 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();
|
||||
bind.MaxReceivedMessageSize = 2147483647;
|
||||
bind.MaxBufferSize = 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;
|
||||
}
|
||||
}
|
||||
|
||||
return connectionBinding;
|
||||
}
|
||||
|
||||
private void stop()
|
||||
{
|
||||
mExecutorManager.Stop();
|
||||
|
||||
lock (mHostLocker)
|
||||
{
|
||||
if (mHost == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
mHost.Close();
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
mHost.Abort();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
mHost = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Stopped != null)
|
||||
{
|
||||
Stopped(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void expert_Deinited(object sender, EventArgs e)
|
||||
{
|
||||
MtExpert expert = (MtExpert)sender;
|
||||
int expertsCount = 0;
|
||||
|
||||
lock (mExpertsLocker)
|
||||
{
|
||||
mExperts.Remove(expert);
|
||||
|
||||
expertsCount = mExperts.Count();
|
||||
}
|
||||
|
||||
mExecutorManager.RemoveCommandExecutor(expert);
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.Deinited -= expert_Deinited;
|
||||
expert.QuoteChanged -= expert_QuoteChanged;
|
||||
|
||||
mService.OnQuoteRemoved(expert.Quote);
|
||||
}
|
||||
|
||||
if (expertsCount == 0)
|
||||
{
|
||||
var stopTimer = new System.Timers.Timer();
|
||||
stopTimer.Elapsed += stopTimer_Elapsed;
|
||||
stopTimer.Interval = STOP_EXPERT_INTERVAL;
|
||||
stopTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
void mExecutorManager_CommandExecuted(object sender, MtCommandExecuteEventArgs e)
|
||||
{
|
||||
EventWaitHandle responseWaiter = null;
|
||||
|
||||
lock (mResponseLocker)
|
||||
{
|
||||
if (mResponseWaiters.ContainsKey(e.Command) == true)
|
||||
{
|
||||
responseWaiter = mResponseWaiters[e.Command];
|
||||
mResponses[e.Command] = e.Response;
|
||||
}
|
||||
}
|
||||
|
||||
if (responseWaiter != null)
|
||||
{
|
||||
responseWaiter.Set();
|
||||
}
|
||||
}
|
||||
|
||||
private void expert_QuoteChanged(MtExpert expert, MtQuote quote)
|
||||
{
|
||||
mService.QuoteUpdate(quote);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
public event EventHandler Stopped;
|
||||
#endregion
|
||||
|
||||
#region IDispose
|
||||
public void Dispose()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private readonly MtService mService;
|
||||
private ServiceHost mHost;
|
||||
|
||||
private readonly MtCommandExecutorManager mExecutorManager;
|
||||
private List<MtExpert> mExperts;
|
||||
|
||||
private readonly Dictionary<MtCommand, EventWaitHandle> mResponseWaiters = new Dictionary<MtCommand, EventWaitHandle>();
|
||||
private readonly Dictionary<MtCommand, MtResponse> mResponses = new Dictionary<MtCommand, MtResponse>();
|
||||
|
||||
private readonly object mResponseLocker = new object();
|
||||
private readonly object mHostLocker = new object();
|
||||
private readonly object mExpertsLocker = new object();
|
||||
private readonly object mCommandExecutorsLocker = new object();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Executable
+190
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ServiceModel;
|
||||
using System.Net;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public class MtServerInstance
|
||||
{
|
||||
#region Init_Instance
|
||||
|
||||
static readonly MtServerInstance mInstance = new MtServerInstance();
|
||||
|
||||
private MtServerInstance()
|
||||
{
|
||||
}
|
||||
|
||||
static MtServerInstance()
|
||||
{
|
||||
}
|
||||
|
||||
public static MtServerInstance GetInstance()
|
||||
{
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Methods
|
||||
public void InitExpert(int expertHandle, string profileName, string symbol, double bid, double ask, IMetaTraderHandler mtHandler)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::InitExpert: symbol = {0}, expertHandle = {1}, profileName = {2}", symbol, expertHandle, profileName);
|
||||
|
||||
if (profileName == null)
|
||||
{
|
||||
string errorMessage = string.Format("Connection profile is null or empty");
|
||||
throw new Exception(errorMessage);
|
||||
}
|
||||
|
||||
MtServer server = null;
|
||||
lock (mServersDictionary)
|
||||
{
|
||||
if (mServersDictionary.ContainsKey(profileName))
|
||||
{
|
||||
server = mServersDictionary[profileName];
|
||||
}
|
||||
else
|
||||
{
|
||||
var profile = MtRegistryManager.LoadConnectionProfile(profileName);
|
||||
|
||||
if (profile == null)
|
||||
{
|
||||
string errorMessage = string.Format("Connection profile '{0}' is not found", profileName);
|
||||
throw new Exception(errorMessage);
|
||||
}
|
||||
|
||||
server = new MtServer(profile);
|
||||
server.Stopped += new EventHandler(server_Stopped);
|
||||
|
||||
mServersDictionary[profile.Name] = server;
|
||||
|
||||
server.Start();
|
||||
}
|
||||
}
|
||||
|
||||
var expert = new MtExpert(expertHandle, new MtQuote(symbol, bid, ask), mtHandler);
|
||||
|
||||
lock(mExpertsDictionary)
|
||||
{
|
||||
mExpertsDictionary[expert.Handle] = expert;
|
||||
}
|
||||
|
||||
server.AddExpert(expert);
|
||||
}
|
||||
|
||||
public void DeinitExpert(int expertHandle)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::DeinitExpert: expertHandle = {0}", expertHandle);
|
||||
|
||||
MtExpert expert = null;
|
||||
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
if (mExpertsDictionary.ContainsKey(expertHandle) == true)
|
||||
{
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
mExpertsDictionary.Remove(expertHandle);
|
||||
}
|
||||
}
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.Deinit();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
}
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.Quote = new MtQuote(symbol, bid, ask);
|
||||
}
|
||||
|
||||
Debug.WriteLine("MtApiServerInstance::SendQuote: finish.");
|
||||
}
|
||||
|
||||
public void SendResponse(int expertHandle, MtResponse response)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::SendResponse: id = {0}, response = {1}", expertHandle, response);
|
||||
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
}
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.SendResponse(response);
|
||||
}
|
||||
|
||||
Debug.WriteLine("MtApiServerInstance::SendResponse: finish");
|
||||
}
|
||||
|
||||
public int GetCommandType(int expertHandle)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::GetCommandType: expertHandle = {0}", expertHandle);
|
||||
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
}
|
||||
|
||||
return (expert != null) ? expert.GetCommandType() : 0;
|
||||
}
|
||||
|
||||
public object GetCommandParameter(int expertHandle, int index)
|
||||
{
|
||||
Debug.WriteLine("MtApiServerInstance::GetCommandParameter: expertHandle = {0}, index = {1}", expertHandle, index);
|
||||
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
}
|
||||
|
||||
return (expert != null) ? expert.GetCommandParameter(index) : null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private void server_Stopped(object sender, EventArgs e)
|
||||
{
|
||||
MtServer server = (MtServer)sender;
|
||||
server.Stopped -= server_Stopped;
|
||||
|
||||
var profile = server.Profile;
|
||||
if (profile != null)
|
||||
{
|
||||
lock (mServersDictionary)
|
||||
{
|
||||
if (mServersDictionary.ContainsKey(profile.Name))
|
||||
{
|
||||
mServersDictionary.Remove(profile.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private readonly MtRegistryManager mConnectionManager = new MtRegistryManager();
|
||||
private readonly Dictionary<string, MtServer> mServersDictionary = new Dictionary<string, MtServer>();
|
||||
private readonly Dictionary<int, MtExpert> mExpertsDictionary = new Dictionary<int, MtExpert>();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Executable
+303
@@ -0,0 +1,303 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ServiceModel;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
[ServiceContract(CallbackContract = typeof(IMtApiCallback), SessionMode = SessionMode.Required)]
|
||||
public interface IMtApi
|
||||
{
|
||||
[OperationContract]
|
||||
bool Connect();
|
||||
|
||||
[OperationContract(IsOneWay = true)]
|
||||
void Disconnect();
|
||||
|
||||
[OperationContract]
|
||||
MtResponse SendCommand(MtCommand command);
|
||||
|
||||
[OperationContract]
|
||||
IEnumerable<MtQuote> GetQuotes();
|
||||
}
|
||||
|
||||
public interface IMtApiCallback
|
||||
{
|
||||
[OperationContract(IsOneWay = true)]
|
||||
void OnQuoteUpdate(MtQuote quote);
|
||||
|
||||
[OperationContract(IsOneWay = true)]
|
||||
void OnServerStopped();
|
||||
|
||||
[OperationContract(IsOneWay = true)]
|
||||
void OnQuoteAdded(MtQuote quote);
|
||||
|
||||
[OperationContract(IsOneWay = true)]
|
||||
void OnQuoteRemoved(MtQuote quote);
|
||||
}
|
||||
|
||||
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,
|
||||
AutomaticSessionShutdown = true,
|
||||
IncludeExceptionDetailInFaults = true,
|
||||
InstanceContextMode = InstanceContextMode.Single)]
|
||||
public sealed class MtService : IMtApi
|
||||
{
|
||||
public MtService(IMtApiServer serverCallback)
|
||||
{
|
||||
if (serverCallback == null)
|
||||
throw new ArgumentNullException("serverCallback");
|
||||
|
||||
mServer = serverCallback;
|
||||
}
|
||||
|
||||
#region IMtApi
|
||||
public bool Connect()
|
||||
{
|
||||
bool connected = false;
|
||||
|
||||
IMtApiCallback callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
||||
|
||||
if (callback != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
mClientsLocker.AcquireWriterLock(10000);
|
||||
|
||||
try
|
||||
{
|
||||
if (mClientCallbacks.Contains(callback) == false)
|
||||
mClientCallbacks.Add(callback);
|
||||
|
||||
connected = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseWriterLock();
|
||||
}
|
||||
}
|
||||
catch (ApplicationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
IMtApiCallback callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
||||
|
||||
if (callback != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
mClientsLocker.AcquireWriterLock(10000);
|
||||
|
||||
try
|
||||
{
|
||||
mClientCallbacks.Remove(callback);
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseWriterLock();
|
||||
}
|
||||
}
|
||||
catch (ApplicationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MtResponse SendCommand(MtCommand command)
|
||||
{
|
||||
return mServer.SendCommand(command);
|
||||
}
|
||||
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
{
|
||||
return mServer.GetQuotes();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void OnStopServer()
|
||||
{
|
||||
try
|
||||
{
|
||||
mClientsLocker.AcquireReaderLock(2000);
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var callback in mClientCallbacks)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback.OnServerStopped();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseReaderLock();
|
||||
}
|
||||
}
|
||||
catch (ApplicationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void QuoteUpdate(MtQuote quote)
|
||||
{
|
||||
try
|
||||
{
|
||||
mClientsLocker.AcquireReaderLock(200);
|
||||
|
||||
List<IMtApiCallback> crashedClientsCallback = null;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var callback in mClientCallbacks)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback.OnQuoteUpdate(quote);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (crashedClientsCallback == null)
|
||||
crashedClientsCallback = new List<IMtApiCallback>();
|
||||
|
||||
crashedClientsCallback.Add(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseReaderLock();
|
||||
}
|
||||
|
||||
removeCrashedClientCallbacks(crashedClientsCallback);
|
||||
}
|
||||
catch (ApplicationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void OnQuoteAdded(MtQuote quote)
|
||||
{
|
||||
try
|
||||
{
|
||||
mClientsLocker.AcquireReaderLock(2000);
|
||||
|
||||
List<IMtApiCallback> crashedClientsCallback = null;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var callback in mClientCallbacks)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback.OnQuoteAdded(quote);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (crashedClientsCallback == null)
|
||||
crashedClientsCallback = new List<IMtApiCallback>();
|
||||
|
||||
crashedClientsCallback.Add(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseReaderLock();
|
||||
}
|
||||
|
||||
removeCrashedClientCallbacks(crashedClientsCallback);
|
||||
}
|
||||
catch (ApplicationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void OnQuoteRemoved(MtQuote quote)
|
||||
{
|
||||
try
|
||||
{
|
||||
mClientsLocker.AcquireReaderLock(2000);
|
||||
|
||||
List<IMtApiCallback> crashedClientsCallback = null;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var callback in mClientCallbacks)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback.OnQuoteRemoved(quote);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (crashedClientsCallback == null)
|
||||
crashedClientsCallback = new List<IMtApiCallback>();
|
||||
|
||||
crashedClientsCallback.Add(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseReaderLock();
|
||||
}
|
||||
|
||||
removeCrashedClientCallbacks(crashedClientsCallback);
|
||||
}
|
||||
catch (ApplicationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void removeCrashedClientCallbacks(List<IMtApiCallback> crashedClientCallbacks)
|
||||
{
|
||||
if (crashedClientCallbacks != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
mClientsLocker.AcquireWriterLock(200);
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var crashedCallback in crashedClientCallbacks)
|
||||
{
|
||||
mClientCallbacks.Remove(crashedCallback);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseWriterLock();
|
||||
}
|
||||
}
|
||||
catch (ApplicationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private readonly IMtApiServer mServer;
|
||||
private readonly List<IMtApiCallback> mClientCallbacks = new List<IMtApiCallback>();
|
||||
private readonly ReaderWriterLock mClientsLocker = new ReaderWriterLock();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MTApiService")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("DW")]
|
||||
[assembly: AssemblyProduct("MTApiService")]
|
||||
[assembly: AssemblyCopyright("Copyright © DW 2011")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("f1cc1516-9352-4ddd-811a-c5fc842b12d4")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.12.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.12.0")]
|
||||
Reference in New Issue
Block a user