Refactored MtApiService: command will be executed in first expert will be invoked by quote tick

This commit is contained in:
DW
2016-04-13 16:41:32 +03:00
parent b803ed8567
commit 6f8a8728ed
7 changed files with 249 additions and 244 deletions
+3 -10
View File
@@ -1,15 +1,8 @@
using System; namespace MTApiService
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MTApiService
{ {
public interface ICommandManager public interface ICommandManager
{ {
void EnqueueCommand(MtCommand command); void EnqueueCommandTask(MtCommandTask task);
MtCommand DequeueCommand(); MtCommandTask DequeueCommandTask();
void OnCommandExecuted(MtExpert expert, MtCommand command, MtResponse response);
} }
} }
+1
View File
@@ -59,6 +59,7 @@
<Compile Include="IMtApiServer.cs" /> <Compile Include="IMtApiServer.cs" />
<Compile Include="MtApiProxy.cs" /> <Compile Include="MtApiProxy.cs" />
<Compile Include="MtClient.cs" /> <Compile Include="MtClient.cs" />
<Compile Include="MtCommandTask.cs" />
<Compile Include="MtMqlBookInfo.cs" /> <Compile Include="MtMqlBookInfo.cs" />
<Compile Include="MtMqlRates.cs" /> <Compile Include="MtMqlRates.cs" />
<Compile Include="MtMqlTick.cs" /> <Compile Include="MtMqlTick.cs" />
+37
View File
@@ -0,0 +1,37 @@
using System.Threading;
namespace MTApiService
{
public class MtCommandTask
{
private readonly EventWaitHandle _responseWaiter = new AutoResetEvent(false);
private MtResponse _result;
private readonly object _locker = new object();
public MtCommandTask(MtCommand command)
{
Command = command;
}
public MtCommand Command { get; private set; }
public MtResponse WaitResult(int time)
{
_responseWaiter.WaitOne(time);
lock (_locker)
{
return _result;
}
}
public void SetResult(MtResponse result)
{
lock (_locker)
{
_result = result;
}
_responseWaiter.Set();
}
}
}
+70 -65
View File
@@ -1,12 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace MTApiService namespace MTApiService
{ {
class MtCommandExecutorManager : ICommandManager internal class MtCommandExecutorManager : ICommandManager
{ {
#region Public Methods #region Public Methods
@@ -14,8 +11,8 @@ namespace MTApiService
{ {
lock (_locker) lock (_locker)
{ {
mCommandExecutors.Clear(); _commandExecutors.Clear();
mCommands.Clear(); _commandTasks.Clear();
} }
} }
@@ -24,26 +21,26 @@ namespace MTApiService
if (commandExecutor == null) if (commandExecutor == null)
return; return;
var notify = false;
lock (_locker) lock (_locker)
{ {
if (mCommandExecutors.Contains(commandExecutor) == true) if (_commandExecutors.Contains(commandExecutor))
return; return;
mCommandExecutors.Add(commandExecutor); _commandExecutors.Add(commandExecutor);
if (_commandTasks.Count > 0)
commandExecutor.CommandManager = this;
if (mCurrentExecutor == null)
{ {
mCurrentExecutor = commandExecutor; notify = true;
mCurrentExecutor.IsCommandExecutor = true;
if (mCommands.Count > 0)
{
mCurrentExecutor.NotifyCommandReady();
}
} }
} }
commandExecutor.CommandExecuted += CommandExecutor_CommandExecuted;
commandExecutor.CommandManager = this;
if (notify)
{
NotifyCommandReady();
}
} }
public void RemoveCommandExecutor(MtExpert commandExecutor) public void RemoveCommandExecutor(MtExpert commandExecutor)
@@ -51,80 +48,88 @@ namespace MTApiService
if (commandExecutor == null) if (commandExecutor == null)
return; return;
var notify = false;
lock (_locker) lock (_locker)
{ {
if (mCommandExecutors.Contains(commandExecutor) == false) if (_commandExecutors.Contains(commandExecutor) == false)
return; return;
mCommandExecutors.Remove(commandExecutor); _commandExecutors.Remove(commandExecutor);
if (_commandTasks.Count > 0)
if (mCurrentExecutor == commandExecutor)
{ {
mCurrentExecutor.IsCommandExecutor = false; notify = true;
mCurrentExecutor = mCommandExecutors.Count > 0 ? mCommandExecutors[0] : null;
if (mCommands.Count > 0)
{
mCurrentExecutor.NotifyCommandReady();
}
} }
} }
commandExecutor.CommandExecuted -= CommandExecutor_CommandExecuted;
commandExecutor.CommandManager = null;
if (notify)
{
NotifyCommandReady();
}
} }
public void EnqueueCommand(MtCommand command) public void EnqueueCommandTask(MtCommandTask task)
{ {
if (command == null) if (task == null)
return; return;
lock (_locker) lock (_locker)
{ {
mCommands.Enqueue(command); _commandTasks.Enqueue(task);
mCurrentExecutor.NotifyCommandReady();
} }
NotifyCommandReady();
} }
public MtCommand DequeueCommand() public MtCommandTask DequeueCommandTask()
{ {
lock (_locker) lock (_locker)
{ {
return mCommands.Count > 0 ? mCommands.Dequeue() : null; return _commandTasks.Count > 0 ? _commandTasks.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 #endregion
#region Events #region Private Methods
public event EventHandler<MtCommandExecuteEventArgs> CommandExecuted; private void NotifyCommandReady()
{
var commandExecutors = new List<MtExpert>();
lock (_locker)
{
commandExecutors.AddRange(_commandExecutors);
}
foreach (var executor in commandExecutors)
{
executor.NotifyCommandReady();
}
}
private void CommandExecutor_CommandExecuted(object sender, EventArgs e)
{
var notify = false;
lock (_locker)
{
if (_commandTasks.Count > 0)
{
notify = true;
}
}
if (notify)
{
NotifyCommandReady();
}
}
#endregion #endregion
#region Private Fields #region Private Fields
private MtExpert mCurrentExecutor; private readonly List<MtExpert> _commandExecutors = new List<MtExpert>();
private readonly Queue<MtCommandTask> _commandTasks = new Queue<MtCommandTask>();
private List<MtExpert> mCommandExecutors = new List<MtExpert>();
private Queue<MtCommand> mCommands = new Queue<MtCommand>();
private readonly object _locker = new object(); private readonly object _locker = new object();
#endregion #endregion
+71 -52
View File
@@ -1,7 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MTApiService namespace MTApiService
{ {
@@ -10,43 +7,46 @@ namespace MTApiService
public delegate void MtQuoteHandler(MtExpert expert, MtQuote quote); public delegate void MtQuoteHandler(MtExpert expert, MtQuote quote);
#region Properties #region Properties
private MtQuote _Quote; private MtQuote _quote;
public MtQuote Quote public MtQuote Quote
{ {
get get
{ {
lock (_locker) lock (_locker)
{ {
return _Quote; return _quote;
} }
} }
set set
{ {
lock(_locker) lock(_locker)
{ {
_Quote = value; _quote = value;
} }
if (QuoteChanged != null) FireOnQuoteChanged(value);
{
QuoteChanged(this, value);
}
} }
} }
public int Handle { get; private set; } public int Handle { get; private set; }
private volatile bool _IsEnable = true; private bool _isEnable = true;
public bool IsEnable public bool IsEnable
{ {
get { return _IsEnable; } get
private set { _IsEnable = value; } {
} lock (_locker)
{
private volatile bool _IsCommandExecutor = true; return _isEnable;
public bool IsCommandExecutor }
{ }
get { return _IsCommandExecutor; } private set
set { _IsCommandExecutor = value; } {
lock (_locker)
{
_isEnable = value;
}
}
} }
public ICommandManager CommandManager public ICommandManager CommandManager
@@ -55,14 +55,14 @@ namespace MTApiService
{ {
lock (_locker) lock (_locker)
{ {
return mCommandManager; return _commandManager;
} }
} }
set set
{ {
lock (_locker) lock (_locker)
{ {
mCommandManager = value; _commandManager = value;
} }
} }
} }
@@ -73,51 +73,43 @@ namespace MTApiService
{ {
Quote = quote; Quote = quote;
Handle = handle; Handle = handle;
mMtHadler = mtHandler; _mtHadler = mtHandler;
} }
public void Deinit() public void Deinit()
{ {
IsEnable = false; IsEnable = false;
FireOnDeinited();
if (Deinited != null)
{
Deinited(this, EventArgs.Empty);
}
} }
public void SendResponse(MtResponse response) public void SendResponse(MtResponse response)
{ {
MtCommand command = mCommand; _commandTask.SetResult(response);
mCommand = null; _commandTask = null;
FireOnCommandExecuted();
ICommandManager commandManager = CommandManager;
if (commandManager != null)
{
commandManager.OnCommandExecuted(this, command, response);
}
} }
public int GetCommandType() public int GetCommandType()
{ {
if (IsCommandExecutor) var commandManager = CommandManager;
if (commandManager != null)
{ {
ICommandManager commandManager = CommandManager; _commandTask = commandManager.DequeueCommandTask();
if (mCommandManager != null)
{
mCommand = mCommandManager.DequeueCommand();
}
} }
return mCommand != null ? mCommand.CommandType : 0; return _commandTask != null && _commandTask.Command != null ? _commandTask.Command.CommandType : 0;
} }
public object GetCommandParameter(int index) public object GetCommandParameter(int index)
{ {
if (mCommand != null && mCommand.Parameters != null if (_commandTask != null)
&& index >= 0 && index < mCommand.Parameters.Count)
{ {
return mCommand.Parameters[index]; var command = _commandTask.Command;
if (command != null && command.Parameters != null
&& index >= 0 && index < command.Parameters.Count)
{
return command.Parameters[index];
}
} }
return null; return null;
@@ -131,13 +123,39 @@ namespace MTApiService
} }
#endregion #endregion
#region Private Methods #region Private Methods
private void SendTickToMetaTrader() private void SendTickToMetaTrader()
{ {
if (mMtHadler != null) if (_mtHadler != null)
{ {
mMtHadler.SendTickToMetaTrader(Handle); _mtHadler.SendTickToMetaTrader(Handle);
}
}
private void FireOnQuoteChanged(MtQuote quote)
{
var handler = QuoteChanged;
if (handler != null)
{
handler(this, quote);
}
}
private void FireOnDeinited()
{
var handler = Deinited;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
private void FireOnCommandExecuted()
{
var handler = CommandExecuted;
if (handler != null)
{
handler(this, EventArgs.Empty);
} }
} }
#endregion #endregion
@@ -145,12 +163,13 @@ namespace MTApiService
#region Events #region Events
public event EventHandler Deinited; public event EventHandler Deinited;
public event MtQuoteHandler QuoteChanged; public event MtQuoteHandler QuoteChanged;
public event EventHandler CommandExecuted;
#endregion #endregion
#region Private Fields #region Private Fields
private readonly IMetaTraderHandler mMtHadler; private readonly IMetaTraderHandler _mtHadler;
private MtCommand mCommand; private MtCommandTask _commandTask;
private ICommandManager mCommandManager; private ICommandManager _commandManager;
private readonly object _locker = new object(); private readonly object _locker = new object();
#endregion #endregion
} }
+67 -117
View File
@@ -1,18 +1,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading;
using System.ServiceModel; using System.ServiceModel;
using System.Net; using System.Net;
using System.Diagnostics; using System.Diagnostics;
using System.ServiceModel.Channels; using System.ServiceModel.Channels;
using System.Runtime.InteropServices;
using System.Net.Sockets; using System.Net.Sockets;
namespace MTApiService namespace MTApiService
{ {
class MtServer : IDisposable, IMtApiServer internal class MtServer : IDisposable, IMtApiServer
{ {
#region Constants #region Constants
private const int WAIT_RESPONSE_TIME = 40000; // 40 sec private const int WAIT_RESPONSE_TIME = 40000; // 40 sec
@@ -23,12 +20,7 @@ namespace MTApiService
public MtServer(int port) public MtServer(int port)
{ {
Port = port; Port = port;
mService = new MtService(this); _service = new MtService(this);
mHosts = new List<ServiceHost>();
mExecutorManager = new MtCommandExecutorManager();
mExecutorManager.CommandExecuted += mExecutorManager_CommandExecuted;
} }
#endregion #endregion
@@ -39,21 +31,18 @@ namespace MTApiService
#region Public Methods #region Public Methods
public void Start() public void Start()
{ {
bool hostsInitialized = InitHosts(Port); var hostsInitialized = InitHosts(Port);
if (hostsInitialized == false) if (hostsInitialized == false)
return;
lock (mExpertsLocker)
{ {
mExperts = new List<MtExpert>(); Debug.WriteLine("Start: InitHosts failed. ");
} }
} }
private bool InitHosts(int port) private bool InitHosts(int port)
{ {
lock (mHostLocker) lock (_hosts)
{ {
if (mHosts.Count > 0) if (_hosts.Count > 0)
return false; return false;
//init local pipe host //init local pipe host
@@ -61,7 +50,7 @@ namespace MTApiService
ServiceHost localServiceHost = CreateServiceHost(localUrl, true); ServiceHost localServiceHost = CreateServiceHost(localUrl, true);
if (localServiceHost != null) if (localServiceHost != null)
{ {
mHosts.Add(localServiceHost); _hosts.Add(localServiceHost);
} }
//init network hosts //init network hosts
@@ -79,7 +68,7 @@ namespace MTApiService
ServiceHost serviceHost = CreateServiceHost(networkUrl, false); ServiceHost serviceHost = CreateServiceHost(networkUrl, false);
if (serviceHost != null) if (serviceHost != null)
{ {
mHosts.Add(serviceHost); _hosts.Add(serviceHost);
} }
} }
} }
@@ -97,8 +86,8 @@ namespace MTApiService
{ {
try try
{ {
serviceHost = new ServiceHost(mService); serviceHost = new ServiceHost(_service);
Binding binding = CreateConnectionBinding(local); var binding = CreateConnectionBinding(local);
serviceHost.AddServiceEndpoint(typeof(IMtApi), binding, serverUrlAdress); serviceHost.AddServiceEndpoint(typeof(IMtApi), binding, serverUrlAdress);
serviceHost.Open(); serviceHost.Open();
@@ -116,17 +105,17 @@ namespace MTApiService
{ {
if (expert != null) if (expert != null)
{ {
expert.Deinited += new EventHandler(expert_Deinited); expert.Deinited += expert_Deinited;
expert.QuoteChanged += new MtExpert.MtQuoteHandler(expert_QuoteChanged); expert.QuoteChanged += expert_QuoteChanged;
lock (mExpertsLocker) lock (_experts)
{ {
mExperts.Add(expert); _experts.Add(expert);
} }
mExecutorManager.AddCommandExecutor(expert); _executorManager.AddCommandExecutor(expert);
mService.OnQuoteAdded(expert.Quote); _service.OnQuoteAdded(expert.Quote);
} }
} }
@@ -140,31 +129,11 @@ namespace MTApiService
if (command != null) if (command != null)
{ {
EventWaitHandle responseWaiter = new AutoResetEvent(false); var task = new MtCommandTask(command);
_executorManager.EnqueueCommandTask(task);
lock (mResponseLocker)
{
mResponseWaiters[command] = responseWaiter;
}
mExecutorManager.EnqueueCommand(command);
//wait for execute command in MetaTrader //wait for execute command in MetaTrader
responseWaiter.WaitOne(WAIT_RESPONSE_TIME); response = task.WaitResult(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; return response;
@@ -172,9 +141,9 @@ namespace MTApiService
public IEnumerable<MtQuote> GetQuotes() public IEnumerable<MtQuote> GetQuotes()
{ {
lock (mExpertsLocker) lock (_experts)
{ {
return (from s in mExperts select s.Quote); return (from s in _experts select s.Quote);
} }
} }
@@ -183,23 +152,26 @@ namespace MTApiService
#region Private Methods #region Private Methods
private void stopTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) private void stopTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{ {
int expertsCount = 0; var expertsCount = 0;
lock (mExpertsLocker) lock (_experts)
{ {
expertsCount = mExperts.Count(); expertsCount = _experts.Count();
} }
if (expertsCount == 0) if (expertsCount == 0)
{ {
mService.OnStopServer(); _service.OnStopServer();
stop(); Stop();
} }
var stopTimer = sender as System.Timers.Timer; var stopTimer = sender as System.Timers.Timer;
stopTimer.Stop(); if (stopTimer != null)
stopTimer.Elapsed -= stopTimer_Elapsed; {
stopTimer.Stop();
stopTimer.Elapsed -= stopTimer_Elapsed;
}
} }
private string CreateConnectionAddress(string host, int port, bool local) private string CreateConnectionAddress(string host, int port, bool local)
@@ -265,65 +237,62 @@ namespace MTApiService
return connectionBinding; return connectionBinding;
} }
private void stop() private void Stop()
{ {
mExecutorManager.Stop(); _executorManager.Stop();
lock (mHostLocker) lock (_hosts)
{ {
if (mHosts.Count == 0) if (_hosts.Count == 0)
return; return;
try try
{ {
foreach (var host in mHosts) foreach (var host in _hosts)
{ {
host.Close(); host.Close();
} }
} }
catch (TimeoutException) catch (TimeoutException)
{ {
foreach (var host in mHosts) foreach (var host in _hosts)
{ {
host.Abort(); host.Abort();
} }
} }
catch (Exception) catch (Exception)
{ {
// ignored
} }
finally finally
{ {
mHosts.Clear(); _hosts.Clear();
} }
} }
if (Stopped != null) FireOnStopped();
{
Stopped(this, EventArgs.Empty);
}
} }
private void expert_Deinited(object sender, EventArgs e) private void expert_Deinited(object sender, EventArgs e)
{ {
MtExpert expert = (MtExpert)sender; if (sender == null)
int expertsCount = 0; return;
lock (mExpertsLocker) var expert = (MtExpert)sender;
var expertsCount = 0;
lock (_experts)
{ {
mExperts.Remove(expert); _experts.Remove(expert);
expertsCount = _experts.Count();
expertsCount = mExperts.Count();
} }
mExecutorManager.RemoveCommandExecutor(expert); _executorManager.RemoveCommandExecutor(expert);
if (expert != null) expert.Deinited -= expert_Deinited;
{ expert.QuoteChanged -= expert_QuoteChanged;
expert.Deinited -= expert_Deinited;
expert.QuoteChanged -= expert_QuoteChanged;
mService.OnQuoteRemoved(expert.Quote); _service.OnQuoteRemoved(expert.Quote);
}
if (expertsCount == 0) if (expertsCount == 0)
{ {
@@ -334,28 +303,18 @@ namespace MTApiService
} }
} }
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) private void expert_QuoteChanged(MtExpert expert, MtQuote quote)
{ {
mService.QuoteUpdate(quote); _service.QuoteUpdate(quote);
}
private void FireOnStopped()
{
var handler = Stopped;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
} }
#endregion #endregion
@@ -367,25 +326,16 @@ namespace MTApiService
#region IDispose #region IDispose
public void Dispose() public void Dispose()
{ {
stop(); Stop();
} }
#endregion #endregion
#region Fields #region Fields
private readonly MtService mService; private readonly MtService _service;
private readonly List<ServiceHost> mHosts; private readonly List<ServiceHost> _hosts = new List<ServiceHost>();
private readonly MtCommandExecutorManager _executorManager = new MtCommandExecutorManager();
private readonly MtCommandExecutorManager mExecutorManager; private readonly List<MtExpert> _experts = new List<MtExpert>();
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 #endregion
} }
} }
BIN
View File
Binary file not shown.