Added projects MtApi4 and MtApi5

This commit is contained in:
Vyacheslav Demidyuk
2014-10-31 09:05:52 +02:00
parent 869d3a117b
commit 8746e96416
178 changed files with 26390 additions and 0 deletions
+15
View File
@@ -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);
}
}
+73
View File
@@ -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;
}
}
}
+12
View File
@@ -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);
}
}
+13
View File
@@ -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();
}
}
+93
View File
@@ -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>
+80
View File
@@ -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
}
}
+305
View File
@@ -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
}
}
+26
View File
@@ -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; }
}
}
+19
View File
@@ -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;
}
}
}
+19
View File
@@ -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; }
}
}
+132
View File
@@ -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
}
}
+157
View File
@@ -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
}
}
+33
View File
@@ -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;
}
}
}
+21
View File
@@ -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; }
}
}
+30
View File
@@ -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
}
}
+27
View File
@@ -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
}
}
+43
View File
@@ -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; }
}
}
+325
View File
@@ -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
}
}
+182
View File
@@ -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; }
}
}
+334
View File
@@ -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
}
}
+190
View File
@@ -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
}
}
+303
View File
@@ -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
}
}
+36
View File
@@ -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")]