mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-07-28 19:17:48 +00:00
259 lines
7.4 KiB
C#
Executable File
259 lines
7.4 KiB
C#
Executable File
using System;
|
|
using System.Collections.Generic;
|
|
using System.ServiceModel;
|
|
using System.Threading;
|
|
using log4net;
|
|
|
|
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]
|
|
List<MtQuote> GetQuotes();
|
|
}
|
|
|
|
[ServiceContract]
|
|
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);
|
|
|
|
[OperationContract(IsOneWay = true)]
|
|
void OnMtEvent(MtEvent ntEvent);
|
|
}
|
|
|
|
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,
|
|
AutomaticSessionShutdown = true,
|
|
IncludeExceptionDetailInFaults = true,
|
|
InstanceContextMode = InstanceContextMode.Single)]
|
|
public sealed class MtService : IMtApi
|
|
{
|
|
private static readonly ILog Log = LogManager.GetLogger(typeof(MtService));
|
|
|
|
public MtService(IMtApiServer serverCallback)
|
|
{
|
|
if (serverCallback == null)
|
|
throw new ArgumentNullException(nameof(serverCallback));
|
|
|
|
_server = serverCallback;
|
|
}
|
|
|
|
#region IMtApi
|
|
public bool Connect()
|
|
{
|
|
Log.Debug("Connect: begin");
|
|
|
|
var callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
|
|
|
if (callback == null)
|
|
{
|
|
Log.Warn("Connect: end. Callback is not definded.");
|
|
return false;
|
|
}
|
|
|
|
var connected = false;
|
|
|
|
try
|
|
{
|
|
_clientsLocker.AcquireWriterLock(10000);
|
|
|
|
try
|
|
{
|
|
if (_clientCallbacks.Contains(callback) == false)
|
|
_clientCallbacks.Add(callback);
|
|
|
|
connected = true;
|
|
}
|
|
finally
|
|
{
|
|
_clientsLocker.ReleaseWriterLock();
|
|
}
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
Log.ErrorFormat("Connect: ApplicationException - {0}", ex.Message);
|
|
}
|
|
|
|
Log.DebugFormat("Connect: end. connected = {0}", connected);
|
|
|
|
return connected;
|
|
}
|
|
|
|
public void Disconnect()
|
|
{
|
|
Log.Debug("Disconnect: begin");
|
|
|
|
var callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
|
|
|
if (callback == null)
|
|
{
|
|
Log.Warn("Disconnect: end. Callback is not definded.");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
_clientsLocker.AcquireWriterLock(10000);
|
|
|
|
try
|
|
{
|
|
_clientCallbacks.Remove(callback);
|
|
}
|
|
finally
|
|
{
|
|
_clientsLocker.ReleaseWriterLock();
|
|
}
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
Log.ErrorFormat("Disconnect: ApplicationException - {0}", ex.Message);
|
|
}
|
|
|
|
Log.Debug("Disconnect: end.");
|
|
}
|
|
|
|
public MtResponse SendCommand(MtCommand command)
|
|
{
|
|
Log.DebugFormat("SendCommand: called. command = {0}", command);
|
|
|
|
return _server.SendCommand(command);
|
|
}
|
|
|
|
public List<MtQuote> GetQuotes()
|
|
{
|
|
Log.Debug("GetQuotes: called.");
|
|
|
|
return _server.GetQuotes();
|
|
}
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
public void OnStopServer()
|
|
{
|
|
Log.Debug("OnStopServer: begin.");
|
|
|
|
ExecuteCallbackAction(a => a.OnServerStopped());
|
|
|
|
Log.Debug("OnStopServer: end.");
|
|
}
|
|
|
|
public void QuoteUpdate(MtQuote quote)
|
|
{
|
|
Log.Debug("QuoteUpdate: begin.");
|
|
|
|
ExecuteCallbackAction(a => a.OnQuoteUpdate(quote));
|
|
|
|
Log.Debug("QuoteUpdate: end.");
|
|
}
|
|
|
|
public void OnQuoteAdded(MtQuote quote)
|
|
{
|
|
Log.Debug("OnQuoteAdded: begin.");
|
|
|
|
ExecuteCallbackAction(a => a.OnQuoteAdded(quote));
|
|
|
|
Log.Debug("OnQuoteAdded: end.");
|
|
}
|
|
|
|
public void OnQuoteRemoved(MtQuote quote)
|
|
{
|
|
Log.Debug("OnQuoteRemoved: begin.");
|
|
|
|
ExecuteCallbackAction(a => a.OnQuoteRemoved(quote));
|
|
|
|
Log.Debug("OnQuoteRemoved: end.");
|
|
}
|
|
|
|
public void OnMtEvent(MtEvent mtEvent)
|
|
{
|
|
Log.Debug("OnMtEvent: begin.");
|
|
|
|
ExecuteCallbackAction(a => a.OnMtEvent(mtEvent));
|
|
|
|
Log.Debug("OnMtEvent: end.");
|
|
}
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
|
|
private void ExecuteCallbackAction(Action<IMtApiCallback> action)
|
|
{
|
|
Log.Debug("ExecuteCallbackAction: begin.");
|
|
|
|
try
|
|
{
|
|
_clientsLocker.AcquireReaderLock(2000);
|
|
|
|
List<IMtApiCallback> crashedClientCallbacks = null;
|
|
|
|
try
|
|
{
|
|
foreach (var callback in _clientCallbacks)
|
|
{
|
|
try
|
|
{
|
|
action(callback);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.ErrorFormat("ExecuteCallbackAction: Exception - {0}", ex.Message);
|
|
|
|
if (crashedClientCallbacks == null)
|
|
crashedClientCallbacks = new List<IMtApiCallback>();
|
|
|
|
crashedClientCallbacks.Add(callback);
|
|
}
|
|
}
|
|
|
|
if (crashedClientCallbacks != null)
|
|
{
|
|
Log.WarnFormat("ExecuteCallbackAction: crashed callback count = {0}", crashedClientCallbacks.Count);
|
|
|
|
foreach (var crashedCallback in crashedClientCallbacks)
|
|
{
|
|
_clientCallbacks.Remove(crashedCallback);
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_clientsLocker.ReleaseReaderLock();
|
|
}
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
Log.ErrorFormat("ExecuteCallbackAction: ApplicationException - {0}", ex.Message);
|
|
}
|
|
|
|
Log.Debug("ExecuteCallbackAction: end.");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Fields
|
|
private readonly IMtApiServer _server;
|
|
private readonly List<IMtApiCallback> _clientCallbacks = new List<IMtApiCallback>();
|
|
private readonly ReaderWriterLock _clientsLocker = new ReaderWriterLock();
|
|
#endregion
|
|
}
|
|
}
|