Added Emesary
This commit is contained in:
@@ -4,11 +4,9 @@
|
||||
*
|
||||
* File Type : Implementation File
|
||||
*
|
||||
* Description : Templated version of Emesary
|
||||
* :
|
||||
* :
|
||||
* :
|
||||
* :
|
||||
* Description : Emesary main.
|
||||
* : This only needs to instance the GlobalTransmitter as all of the
|
||||
* : logic is in the header files (by design)
|
||||
*
|
||||
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
|
||||
*
|
||||
@@ -24,4 +22,10 @@
|
||||
|
||||
#include "simgear/emesary/Emesary.hxx"
|
||||
|
||||
simgear::Emesary::Transmitter GlobalTransmitter;
|
||||
namespace simgear
|
||||
{
|
||||
namespace Emesary
|
||||
{
|
||||
Transmitter GlobalTransmitter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,325 +1,41 @@
|
||||
#pragma once
|
||||
#ifndef EMESARY_hxx
|
||||
#define EMESARY_hxx
|
||||
/*---------------------------------------------------------------------------
|
||||
*
|
||||
* Title : Emesary - class based inter-object communication
|
||||
* Title : Emesary - class based inter-object communication
|
||||
*
|
||||
* File Type : Implementation File
|
||||
* File Type : Implementation File
|
||||
*
|
||||
* Description : Provides generic inter-object communication. For an object to receive a message it
|
||||
* : must first register with a Transmitter, such as GlobalTransmitter, and implement the
|
||||
* : IReceiver interface. That's it.
|
||||
* : To send a message use a Transmitter with an object. That's all there is to it.
|
||||
* Description : Provides generic inter-object communication. For an object to receive a message it
|
||||
* : must first register with a Transmitter, such as GlobalTransmitter, and implement the
|
||||
* : IReceiver interface. That's it.
|
||||
* : To send a message use a Transmitter with an object. That's all there is to it.
|
||||
*
|
||||
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
|
||||
*
|
||||
* Author : Richard Harrison (richard@zaretto.com)
|
||||
* Author : Richard Harrison (richard@zaretto.com)
|
||||
*
|
||||
* Creation Date : 18 March 2002, rewrite 2017
|
||||
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
|
||||
*
|
||||
* Version : $Header: $
|
||||
* Version : $Header: $
|
||||
*
|
||||
* Copyright <EFBFBD> 2002 - 2017 Richard Harrison All Rights Reserved.
|
||||
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
|
||||
*
|
||||
*---------------------------------------------------------------------------*/
|
||||
#include <typeinfo>
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
|
||||
#include "ReceiptStatus.hxx"
|
||||
#include "INotification.hxx"
|
||||
#include "IReceiver.hxx"
|
||||
#include "ITransmitter.hxx"
|
||||
#include "Transmitter.hxx"
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace Emesary
|
||||
{
|
||||
enum ReceiptStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Processing completed successfully
|
||||
/// </summary>
|
||||
ReceiptStatusOK = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Individual item failure
|
||||
/// </summary>
|
||||
ReceiptStatusFail = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Fatal error; stop processing any further recipieints of this message. Implicitly fail
|
||||
/// </summary>
|
||||
ReceiptStatusAbort = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Definitive completion - do not send message to any further recipieints
|
||||
/// </summary>
|
||||
ReceiptStatusFinished = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Return value when method doesn't process a message.
|
||||
/// </summary>
|
||||
ReceiptStatusNotProcessed = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Message has been sent but the return status cannot be determined as it has not been processed by the recipient.
|
||||
/// </summary>
|
||||
/// <notes>
|
||||
/// For example a queue or outgoing bridge
|
||||
/// </notes>
|
||||
ReceiptStatusPending = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Message has been definitively handled but the return value cannot be determined. The message will not be sent any further
|
||||
/// </summary>
|
||||
/// <notes>
|
||||
/// For example a point to point forwarding bridge
|
||||
/// </notes>
|
||||
ReceiptStatusPendingFinished = 6,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Interface (base class) for all notifications. The value is an opaque pointer that may be used to store anything, although
|
||||
/// often it is more convenient to
|
||||
/// </summary>
|
||||
class INotification
|
||||
{
|
||||
public:
|
||||
virtual const char *GetType() = 0;
|
||||
};
|
||||
/// <summary>
|
||||
/// Interface (base class) for a recipeint.
|
||||
/// </summary>
|
||||
class IReceiver
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// Receive notifiction - must be implemented
|
||||
/// </summary>
|
||||
virtual ReceiptStatus Receive(INotification& message) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Called when registered at a transmitter
|
||||
/// </summary>
|
||||
virtual void OnRegisteredAtTransmitter(class Transmitter *p)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Called when de-registered at a transmitter
|
||||
/// </summary>
|
||||
virtual void OnDeRegisteredAtTransmitter(class Transmitter *p)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Interface (base clasee) for a transmitter.
|
||||
/// Transmits Message derived objects. Each instance of this class provides a
|
||||
/// databus to which any number of receivers can attach to.
|
||||
/// </summary>
|
||||
class ITransmitter
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Registers a recipient to receive message from this transmitter
|
||||
*/
|
||||
virtual void Register(IReceiver& R) = 0;
|
||||
/*
|
||||
* Removes a recipient from from this transmitter
|
||||
*/
|
||||
virtual void DeRegister(IReceiver& R) = 0;
|
||||
|
||||
/*
|
||||
* Notify all registered recipients. Stop when receipt status of abort or finished are received.
|
||||
* The receipt status from this method will be
|
||||
* - OK > message handled
|
||||
* - Fail > message not handled. A status of Abort from a recipient will result in our status
|
||||
* being fail as Abort means that the message was not and cannot be handled, and
|
||||
* allows for usages such as access controls.
|
||||
*/
|
||||
virtual ReceiptStatus NotifyAll(INotification& M) = 0;
|
||||
/// <summary>
|
||||
/// number of recipients
|
||||
/// </summary>
|
||||
virtual int Count() = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Description: Transmits Message derived objects. Each instance of this class provides a
|
||||
* databus to which any number of receivers can attach to.
|
||||
*
|
||||
* Messages may be inherited and customised between individual systems.
|
||||
*/
|
||||
class Transmitter : public ITransmitter
|
||||
{
|
||||
protected:
|
||||
typedef std::list<IReceiver *> RecipientList;
|
||||
RecipientList recipient_list;
|
||||
RecipientList deleted_recipients;
|
||||
int CurrentRecipientIndex = 0;
|
||||
SGMutex _lock;
|
||||
std::atomic<int> receiveDepth;
|
||||
std::atomic<int> sentMessageCount;
|
||||
|
||||
void UnlockList()
|
||||
{
|
||||
_lock.unlock();
|
||||
}
|
||||
void LockList()
|
||||
{
|
||||
_lock.lock();
|
||||
}
|
||||
public:
|
||||
Transmitter() : receiveDepth(0), sentMessageCount(0)
|
||||
{
|
||||
}
|
||||
virtual ~Transmitter()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Registers an object to receive messsages from this transmitter.
|
||||
* This object is added to the top of the list of objects to be notified. This is deliberate as
|
||||
* the sequence of registration and message receipt can influence the way messages are processing
|
||||
* when ReceiptStatus of Abort or Finished are encountered. So it was a deliberate decision that the
|
||||
* most recently registered recipients should process the messages/events first.
|
||||
*/
|
||||
virtual void Register(IReceiver& r)
|
||||
{
|
||||
LockList();
|
||||
recipient_list.push_back(&r);
|
||||
r.OnRegisteredAtTransmitter(this);
|
||||
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), &r) != deleted_recipients.end())
|
||||
deleted_recipients.remove(&r);
|
||||
|
||||
UnlockList();
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes an object from receving message from this transmitter
|
||||
*/
|
||||
virtual void DeRegister(IReceiver& R)
|
||||
{
|
||||
LockList();
|
||||
//printf("Remove %x\n", &R);
|
||||
if (recipient_list.size())
|
||||
{
|
||||
if (std::find(recipient_list.begin(), recipient_list.end(), &R) != recipient_list.end())
|
||||
{
|
||||
recipient_list.remove(&R);
|
||||
R.OnDeRegisteredAtTransmitter(this);
|
||||
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), &R) == deleted_recipients.end())
|
||||
deleted_recipients.push_back(&R);
|
||||
}
|
||||
}
|
||||
UnlockList();
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify all registered recipients. Stop when receipt status of abort or finished are received.
|
||||
* The receipt status from this method will be
|
||||
* - OK > message handled
|
||||
* - Fail > message not handled. A status of Abort from a recipient will result in our status
|
||||
* being fail as Abort means that the message was not and cannot be handled, and
|
||||
* allows for usages such as access controls.
|
||||
* NOTE: When I first designed Emesary I always intended to have message routing and the ability
|
||||
* for each recipient to specify an area of interest to allow performance improvements
|
||||
* however this has not yet been implemented - but the concept is still there and
|
||||
* could be implemented by extending the IReceiver interface to allow for this.
|
||||
*/
|
||||
virtual ReceiptStatus NotifyAll(INotification& M)
|
||||
{
|
||||
ReceiptStatus return_status = ReceiptStatusNotProcessed;
|
||||
//printf("Begin receive %d : %x\n", (int)receiveDepth, M);
|
||||
//fflush(stdout);
|
||||
sentMessageCount++;
|
||||
try
|
||||
{
|
||||
LockList();
|
||||
if (receiveDepth == 0)
|
||||
deleted_recipients.clear();
|
||||
receiveDepth++;
|
||||
std::vector<IReceiver*> temp(recipient_list.size());
|
||||
int idx = 0;
|
||||
for (RecipientList::iterator i = recipient_list.begin(); i != recipient_list.end(); i++)
|
||||
{
|
||||
temp[idx++] = *i;
|
||||
}
|
||||
UnlockList();
|
||||
int tempSize = temp.size();
|
||||
for (int index = 0; index < tempSize; index++)
|
||||
{
|
||||
IReceiver* R = temp[index];
|
||||
LockList();
|
||||
if (deleted_recipients.size())
|
||||
{
|
||||
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), R) != deleted_recipients.end())
|
||||
{
|
||||
UnlockList();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
UnlockList();
|
||||
if (R)
|
||||
{
|
||||
ReceiptStatus rstat = R->Receive(M);
|
||||
switch (rstat)
|
||||
{
|
||||
case ReceiptStatusFail:
|
||||
return_status = ReceiptStatusFail;
|
||||
break;
|
||||
case ReceiptStatusPending:
|
||||
return_status = ReceiptStatusPending;
|
||||
break;
|
||||
case ReceiptStatusPendingFinished:
|
||||
return rstat;
|
||||
|
||||
case ReceiptStatusNotProcessed:
|
||||
break;
|
||||
case ReceiptStatusOK:
|
||||
if (return_status == ReceiptStatusNotProcessed)
|
||||
return_status = rstat;
|
||||
break;
|
||||
|
||||
case ReceiptStatusAbort:
|
||||
return ReceiptStatusAbort;
|
||||
|
||||
case ReceiptStatusFinished:
|
||||
return ReceiptStatusOK;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw;
|
||||
// return_status = ReceiptStatusAbort;
|
||||
}
|
||||
receiveDepth--;
|
||||
//printf("End receive %d : %x\n", (int) receiveDepth, M);
|
||||
return return_status;
|
||||
}
|
||||
virtual int Count()
|
||||
{
|
||||
LockList();
|
||||
return recipient_list.size();
|
||||
UnlockList();
|
||||
}
|
||||
int SentMessageCount()
|
||||
{
|
||||
return sentMessageCount;
|
||||
}
|
||||
static bool Failed(ReceiptStatus receiptStatus)
|
||||
{
|
||||
//
|
||||
// failed is either Fail or Abort.
|
||||
// NotProcessed isn't a failure because it hasn't been processed.
|
||||
return receiptStatus == ReceiptStatusFail
|
||||
|| receiptStatus == ReceiptStatusAbort;
|
||||
}
|
||||
};
|
||||
Transmitter GlobalTransmitter;
|
||||
// default system wide instance of transmitter object.
|
||||
extern Transmitter GlobalTransmitter;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
54
simgear/emesary/INotification.hxx
Normal file
54
simgear/emesary/INotification.hxx
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef INOTIFICATION_hxx
|
||||
#define INOTIFICATION_hxx
|
||||
/*---------------------------------------------------------------------------
|
||||
*
|
||||
* Title : Emesary - Notification base class
|
||||
*
|
||||
* File Type : Implementation File
|
||||
*
|
||||
* Description : Base class (interface) for all Notifications.
|
||||
* : This is also compatible with the usual implementation of how we
|
||||
* : implement queued notifications.
|
||||
*
|
||||
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
|
||||
*
|
||||
* Author : Richard Harrison (richard@zaretto.com)
|
||||
*
|
||||
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
|
||||
*
|
||||
* Version : $Header: $
|
||||
*
|
||||
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
|
||||
*
|
||||
*---------------------------------------------------------------------------*/
|
||||
namespace simgear
|
||||
{
|
||||
namespace Emesary
|
||||
{
|
||||
/// Interface (base class) for all notifications.
|
||||
class INotification
|
||||
{
|
||||
public:
|
||||
// text representation of notification type. must be unique across all notifications
|
||||
virtual const char *GetType() = 0;
|
||||
|
||||
/// Used to control the sending of notifications. If this returns false then the Transmitter
|
||||
/// should not send this notification.
|
||||
virtual bool IsReadyToSend() { return true; }
|
||||
|
||||
/// Used to control the timeout. If this notification has timed out - then the processor is entitled
|
||||
/// to true.
|
||||
virtual bool IsTimedOut() { return false; }
|
||||
|
||||
/// when this notification has completed the processing recipient must set this to true.
|
||||
/// the processing recipient is responsible for follow on notifications.
|
||||
/// a notification can remain as complete until the transmit queue decides to remove it from the queue.
|
||||
/// there is no requirement that elements are removed immediately upon completion merely that once complete
|
||||
/// the transmitter should not notify any more elements.
|
||||
/// The current notification loop may be completed - following the usual convention unless Completed or Abort
|
||||
/// is returned as the status.
|
||||
virtual bool IsComplete() { return true; }
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
47
simgear/emesary/IReceiver.hxx
Normal file
47
simgear/emesary/IReceiver.hxx
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef IRECEIVER_hxx
|
||||
#define IRECEIVER_hxx
|
||||
/*---------------------------------------------------------------------------
|
||||
*
|
||||
* Title : Emesary - Receiver base class
|
||||
*
|
||||
* File Type : Implementation File
|
||||
*
|
||||
* Description : Base class for all recipients.
|
||||
*
|
||||
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
|
||||
*
|
||||
* Author : Richard Harrison (richard@zaretto.com)
|
||||
*
|
||||
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
|
||||
*
|
||||
* Version : $Header: $
|
||||
*
|
||||
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
|
||||
*
|
||||
*---------------------------------------------------------------------------*/
|
||||
namespace simgear
|
||||
{
|
||||
namespace Emesary
|
||||
{
|
||||
|
||||
/// Interface (base class) for a recipeint.
|
||||
class IReceiver
|
||||
{
|
||||
public:
|
||||
/// Receive notification - must be implemented
|
||||
virtual ReceiptStatus Receive(INotification& message) = 0;
|
||||
|
||||
/// Called when registered at a transmitter
|
||||
virtual void OnRegisteredAtTransmitter(class Transmitter *p)
|
||||
{
|
||||
}
|
||||
|
||||
/// Called when de-registered at a transmitter
|
||||
virtual void OnDeRegisteredAtTransmitter(class Transmitter *p)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
52
simgear/emesary/ITransmitter.hxx
Normal file
52
simgear/emesary/ITransmitter.hxx
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef ITRANSMITTER_hxx
|
||||
#define ITRANSMITTER_hxx
|
||||
/*---------------------------------------------------------------------------
|
||||
*
|
||||
* Title : Emesary - Transmitter base class
|
||||
*
|
||||
* File Type : Implementation File
|
||||
*
|
||||
* Description : Base class for all transmitters.
|
||||
*
|
||||
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
|
||||
*
|
||||
* Author : Richard Harrison (richard@zaretto.com)
|
||||
*
|
||||
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
|
||||
*
|
||||
* Version : $Header: $
|
||||
*
|
||||
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
|
||||
*
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace Emesary
|
||||
{
|
||||
/// Interface (base clasee) for a transmitter.
|
||||
/// Transmits Message derived objects. Each instance of this class provides a
|
||||
/// event/databus to which any number of receivers can attach to.
|
||||
class ITransmitter
|
||||
{
|
||||
public:
|
||||
// Registers a recipient to receive message from this transmitter
|
||||
virtual void Register(IReceiver& R) = 0;
|
||||
// Removes a recipient from from this transmitter
|
||||
virtual void DeRegister(IReceiver& R) = 0;
|
||||
|
||||
|
||||
//Notify all registered recipients. Stop when receipt status of abort or finished are received.
|
||||
//The receipt status from this method will be
|
||||
// - OK > message handled
|
||||
// - Fail > message not handled. A status of Abort from a recipient will result in our status
|
||||
// being fail as Abort means that the message was not and cannot be handled, and
|
||||
// allows for usages such as access controls.
|
||||
virtual ReceiptStatus NotifyAll(INotification& M) = 0;
|
||||
|
||||
/// number of recipients
|
||||
virtual int Count() = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
54
simgear/emesary/ReceiptStatus.hxx
Normal file
54
simgear/emesary/ReceiptStatus.hxx
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef RECEIPTSTATUS_hxx
|
||||
#define RECEIPTSTATUS_hxx
|
||||
/*---------------------------------------------------------------------------
|
||||
*
|
||||
* Title : Emesary - Transmitter base class
|
||||
*
|
||||
* File Type : Implementation File
|
||||
*
|
||||
* Description : Defines the receipt status that can be returned from
|
||||
* : a receive method.
|
||||
*
|
||||
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
|
||||
*
|
||||
* Author : Richard Harrison (richard@zaretto.com)
|
||||
*
|
||||
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
|
||||
*
|
||||
* Version : $Header: $
|
||||
*
|
||||
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
|
||||
*
|
||||
*---------------------------------------------------------------------------*/
|
||||
namespace simgear
|
||||
{
|
||||
namespace Emesary
|
||||
{
|
||||
enum ReceiptStatus
|
||||
{
|
||||
/// Processing completed successfully
|
||||
ReceiptStatusOK = 0,
|
||||
|
||||
/// Individual item failure
|
||||
ReceiptStatusFail = 1,
|
||||
|
||||
/// Fatal error; stop processing any further recipieints of this message. Implicitly fail
|
||||
ReceiptStatusAbort = 2,
|
||||
|
||||
/// Definitive completion - do not send message to any further recipieints
|
||||
ReceiptStatusFinished = 3,
|
||||
|
||||
/// Return value when method doesn't process a message.
|
||||
ReceiptStatusNotProcessed = 4,
|
||||
|
||||
/// Message has been sent but the return status cannot be determined as it has not been processed by the recipient.
|
||||
/// e.g. a queue or outgoing bridge
|
||||
ReceiptStatusPending = 5,
|
||||
|
||||
/// Message has been definitively handled but the return value cannot be determined. The message will not be sent any further
|
||||
/// e.g. a point to point forwarding bridge
|
||||
ReceiptStatusPendingFinished = 6,
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
202
simgear/emesary/Transmitter.hxx
Normal file
202
simgear/emesary/Transmitter.hxx
Normal file
@@ -0,0 +1,202 @@
|
||||
#ifndef TRANSMITTER_hxx
|
||||
#define TRANSMITTER_hxx
|
||||
/*---------------------------------------------------------------------------
|
||||
*
|
||||
* Title : Emesary - Transmitter base class
|
||||
*
|
||||
* File Type : Implementation File
|
||||
*
|
||||
* Description : Defines the receipt status that can be returned from
|
||||
* : a receive method.
|
||||
*
|
||||
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
|
||||
*
|
||||
* Author : Richard Harrison (richard@zaretto.com)
|
||||
*
|
||||
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
|
||||
*
|
||||
* Version : $Header: $
|
||||
*
|
||||
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
|
||||
*
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace Emesary
|
||||
{
|
||||
// Implementation of a ITransmitter
|
||||
class Transmitter : public ITransmitter
|
||||
{
|
||||
protected:
|
||||
typedef std::list<IReceiver *> RecipientList;
|
||||
RecipientList recipient_list;
|
||||
RecipientList deleted_recipients;
|
||||
int CurrentRecipientIndex = 0;
|
||||
SGMutex _lock;
|
||||
std::atomic<int> receiveDepth;
|
||||
std::atomic<int> sentMessageCount;
|
||||
|
||||
void UnlockList()
|
||||
{
|
||||
_lock.unlock();
|
||||
}
|
||||
void LockList()
|
||||
{
|
||||
_lock.lock();
|
||||
}
|
||||
public:
|
||||
Transmitter() : receiveDepth(0), sentMessageCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Transmitter()
|
||||
{
|
||||
}
|
||||
|
||||
// Registers an object to receive messsages from this transmitter.
|
||||
// This object is added to the top of the list of objects to be notified. This is deliberate as
|
||||
// the sequence of registration and message receipt can influence the way messages are processing
|
||||
// when ReceiptStatus of Abort or Finished are encountered. So it was a deliberate decision that the
|
||||
// most recently registered recipients should process the messages/events first.
|
||||
virtual void Register(IReceiver& r)
|
||||
{
|
||||
LockList();
|
||||
recipient_list.push_back(&r);
|
||||
r.OnRegisteredAtTransmitter(this);
|
||||
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), &r) != deleted_recipients.end())
|
||||
deleted_recipients.remove(&r);
|
||||
|
||||
UnlockList();
|
||||
}
|
||||
|
||||
// Removes an object from receving message from this transmitter
|
||||
virtual void DeRegister(IReceiver& R)
|
||||
{
|
||||
LockList();
|
||||
//printf("Remove %x\n", &R);
|
||||
if (recipient_list.size())
|
||||
{
|
||||
if (std::find(recipient_list.begin(), recipient_list.end(), &R) != recipient_list.end())
|
||||
{
|
||||
recipient_list.remove(&R);
|
||||
R.OnDeRegisteredAtTransmitter(this);
|
||||
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), &R) == deleted_recipients.end())
|
||||
deleted_recipients.push_back(&R);
|
||||
}
|
||||
}
|
||||
UnlockList();
|
||||
}
|
||||
|
||||
// Notify all registered recipients. Stop when receipt status of abort or finished are received.
|
||||
// The receipt status from this method will be
|
||||
// - OK > message handled
|
||||
// - Fail > message not handled. A status of Abort from a recipient will result in our status
|
||||
// being fail as Abort means that the message was not and cannot be handled, and
|
||||
// allows for usages such as access controls.
|
||||
virtual ReceiptStatus NotifyAll(INotification& M)
|
||||
{
|
||||
ReceiptStatus return_status = ReceiptStatusNotProcessed;
|
||||
|
||||
sentMessageCount++;
|
||||
try
|
||||
{
|
||||
LockList();
|
||||
if (receiveDepth == 0)
|
||||
deleted_recipients.clear();
|
||||
receiveDepth++;
|
||||
std::vector<IReceiver*> temp(recipient_list.size());
|
||||
int idx = 0;
|
||||
for (RecipientList::iterator i = recipient_list.begin(); i != recipient_list.end(); i++)
|
||||
{
|
||||
temp[idx++] = *i;
|
||||
}
|
||||
UnlockList();
|
||||
int tempSize = temp.size();
|
||||
for (int index = 0; index < tempSize; index++)
|
||||
{
|
||||
IReceiver* R = temp[index];
|
||||
LockList();
|
||||
if (deleted_recipients.size())
|
||||
{
|
||||
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), R) != deleted_recipients.end())
|
||||
{
|
||||
UnlockList();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
UnlockList();
|
||||
if (R)
|
||||
{
|
||||
ReceiptStatus rstat = R->Receive(M);
|
||||
switch (rstat)
|
||||
{
|
||||
case ReceiptStatusFail:
|
||||
return_status = ReceiptStatusFail;
|
||||
break;
|
||||
case ReceiptStatusPending:
|
||||
return_status = ReceiptStatusPending;
|
||||
break;
|
||||
case ReceiptStatusPendingFinished:
|
||||
return rstat;
|
||||
|
||||
case ReceiptStatusNotProcessed:
|
||||
break;
|
||||
case ReceiptStatusOK:
|
||||
if (return_status == ReceiptStatusNotProcessed)
|
||||
return_status = rstat;
|
||||
break;
|
||||
|
||||
case ReceiptStatusAbort:
|
||||
return ReceiptStatusAbort;
|
||||
|
||||
case ReceiptStatusFinished:
|
||||
return ReceiptStatusOK;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw;
|
||||
// return_status = ReceiptStatusAbort;
|
||||
}
|
||||
receiveDepth--;
|
||||
return return_status;
|
||||
}
|
||||
|
||||
// number of currently registered recipients
|
||||
virtual int Count()
|
||||
{
|
||||
LockList();
|
||||
return recipient_list.size();
|
||||
UnlockList();
|
||||
}
|
||||
|
||||
// number of sent messages.
|
||||
int SentMessageCount()
|
||||
{
|
||||
return sentMessageCount;
|
||||
}
|
||||
|
||||
// ascertain if a receipt status can be interpreted as failure.
|
||||
static bool Failed(ReceiptStatus receiptStatus)
|
||||
{
|
||||
//
|
||||
// failed is either Fail or Abort.
|
||||
// NotProcessed isn't a failure because it hasn't been processed.
|
||||
return receiptStatus == ReceiptStatusFail
|
||||
|| receiptStatus == ReceiptStatusAbort;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,13 +1,12 @@
|
||||
#ifndef NOTIFICATIONS_hxx
|
||||
#define NOTIFICATIONS_hxx
|
||||
/*---------------------------------------------------------------------------
|
||||
*
|
||||
* Title : Emesary - class based inter-object communication
|
||||
*
|
||||
* File Type : Implementation File
|
||||
*
|
||||
* Description : Provides generic inter-object communication. For an object to receive a message it
|
||||
* : must first register with a Transmitter, such as GlobalTransmitter, and implement the
|
||||
* : IReceiver interface. That's it.
|
||||
* : To send a message use a Transmitter with an object. That's all there is to it.
|
||||
* Description : simgear notifications
|
||||
*
|
||||
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
|
||||
*
|
||||
@@ -20,16 +19,8 @@
|
||||
* Copyright <20> 2002 - 2017 Richard Harrison All Rights Reserved.
|
||||
*
|
||||
*---------------------------------------------------------------------------*/
|
||||
#include <typeinfo>
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <Windows.h>
|
||||
#include <process.h>
|
||||
#include <atomic>
|
||||
#include <simgear/emesary/emesary.hxx>
|
||||
#include "INotification.hxx"
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
@@ -73,4 +64,5 @@ namespace simgear
|
||||
bool Active;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -27,6 +27,7 @@ set(SOURCES
|
||||
NasalHash.cxx
|
||||
NasalString.cxx
|
||||
NasalObject.cxx
|
||||
NasalEmesaryInterface.cxx
|
||||
detail/from_nasal_helper.cxx
|
||||
detail/to_nasal_helper.cxx
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user