Files

259 lines
7.5 KiB
C#
Raw Permalink Normal View History

2014-10-31 09:05:52 +02:00
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Threading;
using log4net;
2014-10-31 09:05:52 +02:00
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();
2014-10-31 09:05:52 +02:00
}
[ServiceContract]
2014-10-31 09:05:52 +02:00
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);
2014-10-31 09:05:52 +02:00
}
[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));
2014-10-31 09:05:52 +02:00
public MtService(IMtApiServer serverCallback)
{
if (serverCallback == null)
throw new ArgumentNullException(nameof(serverCallback));
2014-10-31 09:05:52 +02:00
_server = serverCallback;
2014-10-31 09:05:52 +02:00
}
#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 defined.");
return false;
}
2014-10-31 09:05:52 +02:00
var connected = false;
2014-10-31 09:05:52 +02:00
try
2014-10-31 09:05:52 +02:00
{
_clientsLocker.AcquireWriterLock(10000);
2014-10-31 09:05:52 +02:00
try
{
if (_clientCallbacks.Contains(callback) == false)
_clientCallbacks.Add(callback);
2014-10-31 09:05:52 +02:00
connected = true;
2014-10-31 09:05:52 +02:00
}
finally
2014-10-31 09:05:52 +02:00
{
_clientsLocker.ReleaseWriterLock();
2014-10-31 09:05:52 +02:00
}
}
catch (ApplicationException ex)
{
Log.ErrorFormat("Connect: ApplicationException - {0}", ex.Message);
}
Log.DebugFormat("Connect: end. connected = {0}", connected);
2014-10-31 09:05:52 +02:00
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;
}
2014-10-31 09:05:52 +02:00
try
2014-10-31 09:05:52 +02:00
{
_clientsLocker.AcquireWriterLock(10000);
2014-10-31 09:05:52 +02:00
try
{
_clientCallbacks.Remove(callback);
2014-10-31 09:05:52 +02:00
}
finally
2014-10-31 09:05:52 +02:00
{
_clientsLocker.ReleaseWriterLock();
2014-10-31 09:05:52 +02:00
}
}
catch (ApplicationException ex)
{
Log.ErrorFormat("Disconnect: ApplicationException - {0}", ex.Message);
}
Log.Debug("Disconnect: end.");
2014-10-31 09:05:52 +02:00
}
public MtResponse SendCommand(MtCommand command)
{
Log.DebugFormat("SendCommand: called. command = {0}", command);
return _server.SendCommand(command);
2014-10-31 09:05:52 +02:00
}
public List<MtQuote> GetQuotes()
2014-10-31 09:05:52 +02:00
{
Log.Debug("GetQuotes: called.");
return _server.GetQuotes();
2014-10-31 09:05:52 +02:00
}
#endregion
#region Public Methods
public void OnStopServer()
{
Log.Debug("OnStopServer: begin.");
ExecuteCallbackAction(a => a.OnServerStopped());
Log.Debug("OnStopServer: end.");
2014-10-31 09:05:52 +02:00
}
public void QuoteUpdate(MtQuote quote)
{
Log.DebugFormat("QuoteUpdate: begin. quote = {0}", quote);
ExecuteCallbackAction(a => a.OnQuoteUpdate(quote));
Log.Debug("QuoteUpdate: end.");
2014-10-31 09:05:52 +02:00
}
public void OnQuoteAdded(MtQuote quote)
{
Log.DebugFormat("OnQuoteAdded: begin. quote = {0}", quote);
ExecuteCallbackAction(a => a.OnQuoteAdded(quote));
Log.Debug("OnQuoteAdded: end.");
}
2014-10-31 09:05:52 +02:00
public void OnQuoteRemoved(MtQuote quote)
{
Log.DebugFormat("OnQuoteRemoved: begin. quote = {0}", quote);
ExecuteCallbackAction(a => a.OnQuoteRemoved(quote));
Log.Debug("OnQuoteRemoved: end.");
}
2014-10-31 09:05:52 +02:00
public void OnMtEvent(MtEvent e)
{
Log.DebugFormat("OnMtEvent: begin.quote = {0}", e);
ExecuteCallbackAction(a => a.OnMtEvent(e));
Log.Debug("OnMtEvent: end.");
2014-10-31 09:05:52 +02:00
}
#endregion
2014-10-31 09:05:52 +02:00
#region Private Methods
private void ExecuteCallbackAction(Action<IMtApiCallback> action)
2014-10-31 09:05:52 +02:00
{
Log.Debug("ExecuteCallbackAction: begin.");
2014-10-31 09:05:52 +02:00
try
{
_clientsLocker.AcquireReaderLock(2000);
2014-10-31 09:05:52 +02:00
List<IMtApiCallback> crashedClientCallbacks = null;
2014-10-31 09:05:52 +02:00
try
{
foreach (var callback in _clientCallbacks)
2014-10-31 09:05:52 +02:00
{
try
{
action(callback);
2014-10-31 09:05:52 +02:00
}
catch (Exception ex)
2014-10-31 09:05:52 +02:00
{
Log.ErrorFormat("ExecuteCallbackAction: Exception - {0}", ex.Message);
if (crashedClientCallbacks == null)
crashedClientCallbacks = new List<IMtApiCallback>();
2014-10-31 09:05:52 +02:00
crashedClientCallbacks.Add(callback);
2014-10-31 09:05:52 +02:00
}
}
if (crashedClientCallbacks != null)
2014-10-31 09:05:52 +02:00
{
Log.WarnFormat("ExecuteCallbackAction: crashed callback count = {0}", crashedClientCallbacks.Count);
2014-10-31 09:05:52 +02:00
foreach (var crashedCallback in crashedClientCallbacks)
{
_clientCallbacks.Remove(crashedCallback);
2014-10-31 09:05:52 +02:00
}
}
}
finally
2014-10-31 09:05:52 +02:00
{
_clientsLocker.ReleaseReaderLock();
2014-10-31 09:05:52 +02:00
}
}
catch (ApplicationException ex)
{
Log.ErrorFormat("ExecuteCallbackAction: ApplicationException - {0}", ex.Message);
}
Log.Debug("ExecuteCallbackAction: end.");
2014-10-31 09:05:52 +02:00
}
#endregion
#region Fields
private readonly IMtApiServer _server;
private readonly List<IMtApiCallback> _clientCallbacks = new List<IMtApiCallback>();
private readonly ReaderWriterLock _clientsLocker = new ReaderWriterLock();
2014-10-31 09:05:52 +02:00
#endregion
}
}