Emesary: Difference between revisions

Jump to navigation Jump to search
12,339 bytes added ,  11 May 2016
Line 74: Line 74:
Collection of examples discussed on the forum.
Collection of examples discussed on the forum.
=== MP Traffic feeds (injection) ===
=== MP Traffic feeds (injection) ===
* https://forum.flightgear.org/viewtopic.php?f=27&t=29355&p=282755#p282431  
* https://forum.flightgear.org/viewtopic.php?f=27&t=29355&p=282755#p282431
 
== JavaScript port ==
{{WIP}}
 
<syntaxhighlight lang="javascript">
//---------------------------------------------------------------------------
//
// Title                : EMESARY 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 an instance of a Transmitter, and provide a Receive method
//
//                     : 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
//                      : http://chateau-logic.com/content/emesary-efficient-inter-object-communication-using-interfaces-and-inheritance
//                      : http://chateau-logic.com/content/c-wpf-application-plumbing-using-emesary
//
// Author              : Richard Harrison (richard@zaretto.com)
//
// Creation Date        : 29 January 2016
//
// Version              : 4.8
//
//  Copyright � 2016 Richard Harrison          Released under GPL V2
//
//---------------------------------------------------------------------------*/
 
function print () {
var i, msg="";
for(i=0; i<arguments.length; i++)
  msg += arguments[i];
console.log(msg);
}
 
function inherit(parent) {
    return Object.create(parent);
}
 
var Transmitter =
{
    ReceiptStatus_OK : 0,          // Processing completed successfully
    ReceiptStatus_Fail : 1,        // Processing resulted in at least one failure
    ReceiptStatus_Abort : 2,      // Fatal error, stop processing any further recipieints of this message. Implicitly failed.
    ReceiptStatus_Finished : 3,    // Definitive completion - do not send message to any further recipieints
    ReceiptStatus_NotProcessed : 4,// Return value when method doesn't process a message.
    ReceiptStatus_Pending : 5,    // Message sent with indeterminate return status as processing underway
    ReceiptStatus_PendingFinished : 6,// Message definitively handled, status indeterminate. The message will not be sent any further
 
    new: function(_ident)
    {
        var new_class = inherit(Transmitter);
        new_class.Recipients = [];
        new_class.Ident = _ident;
        return new_class;
    },
 
    // Add a recipient to receive notifications from this transmitter
    Register: function (recipient)
    {
        this.Recipients.push(recipient);
    },
 
    // Stops a recipient from receiving notifications from this transmitter.
    DeRegister: function(todelete_recipient)
    {
        var out_idx = 0;
        var element_deleted = 0;
 
        for (var idx = 0; idx < this.Recipients.length; idx += 1)
        {
            if (this.Recipients[idx] != todelete_recipient)
            {
                this.Recipients[out_idx] = this.Recipients[idx];
                out_idx = out_idx + 1;
            }
            else
                element_deleted = 1;
        }
 
        if (element_deleted)
            this.Recipients.pop();
    },
 
    RecipientCount: function ()
    {
        return this.Recipients.length;
    },
 
    PrintRecipients: function ()
    {
        print("Recipient list");
        for (var idx = 0; idx < this.Recipients.length; idx += 1)
            print("Recpient ",idx," ",this.Recipients[idx].Ident);
    },
 
    // Notify all registered recipients. Stop when receipt status of abort || 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.
    NotifyAll: function(message)
    {
        var return_status = Transmitter.ReceiptStatus_NotProcessed;
var recipient;
        this.Recipients.forEach( function(recipient, index, array)
        {
            if (recipient.Active)
            {
            var rstat = recipient.Receive(message);
            if(rstat == Transmitter.ReceiptStatus_Fail)
            {
                return_status = Transmitter.ReceiptStatus_Fail;
            }
            else if(rstat == Transmitter.ReceiptStatus_Pending)
            {
                return_status = Transmitter.ReceiptStatus_Pending;
            }
            else if(rstat == Transmitter.ReceiptStatus_PendingFinished)
            {
                return rstat;
            }
//            else if(rstat == Transmitter.ReceiptStatus_NotProcessed)
//            {
//                ;
//            }
            else if(rstat == Transmitter.ReceiptStatus_OK)
            {
                if (return_status == Transmitter.ReceiptStatus_NotProcessed)
                    return_status = rstat;
            }
            else if(rstat == Transmitter.ReceiptStatus_Abort)
            {
                return Transmitter.ReceiptStatus_Abort;
            }
            else if(rstat == Transmitter.ReceiptStatus_Finished)
            {
                return Transmitter.ReceiptStatus_OK;
            }
        }
        });
        return return_status;
    },
    // Returns true if a return value from NotifyAll is to be considered a failure.
    IsFailed: function(receiptStatus)
    {
        // Failed is either Fail || Abort.
        // NotProcessed isn't a failure because it hasn't been processed.
        if (receiptStatus == Transmitter.ReceiptStatus_Fail || receiptStatus == Transmitter.ReceiptStatus_Abort)
            return 1;
        return 0;
    }
};
 
//
//
// Base class for Notifications. By convention a Notification has a type and a value.
//  SubClasses can add extra properties || methods.
var Notification =
{
    new: function(_type, _value)
    {
        var new_class = inherit(Notification);
        new_class.Value = _value;
        new_class.Type = _type;
        return new_class;
    },
};
 
var Recipient =
{
    new: function(_ident)
    {
        var new_class = inherit(Recipient);
        if (_ident === undefined || _ident === "")
        {
            _ident = id(new_class);
            print("ERROR: Ident required when creating a recipient, defaulting to ",_ident);
        }
        return Recipient.construct(_ident, new_class);
    },
    construct: function(_ident, new_class)
    {
console.log("constructing recipient");
        new_class.Ident = _ident;
        new_class.Active = 1;
        new_class.Receive = function(notification)
    {
        print("ERROR: Receive function not implemented in recipient ",this.Ident);
        return Transmitter.ReceiptStatus_NotProcessed;
        };
        return new_class;
    },
};
 
 
//
// Instantiate a Global Transmitter
var GlobalTransmitter =  Transmitter.new("GlobalTransmitter");
 
 
//---------------------------------------------------------------------------
//
// Title                : EMESARY tests
//
// File Type            : Implementation File
//
// Author              : Richard Harrison (richard@zaretto.com)
//
// Creation Date        : 29 January 2016
//
//  Copyright � 2016 Richard Harrison          Released under GPL V2
//
//---------------------------------------------------------------------------*/
 
print("Emesary tests");
 
var TestFailCount = 0;
var TestSuccessCount = 0;
 
var TestNotification =
{
    new: function(_value)
    {
        var new_class = Notification.new("TestNotification", _value);
        return new_class;
    },
};
var TestNotProcessedNotification =
{
    new: function(_value)
    {
        var new_class = Notification.new("TestNotProcessedNotification", _value);
        return new_class;
    },
};
var RadarReturnNotification =
{
    new: function(_value, _x, _y, _z)
    {
        var new_class = Notification.new("RadarReturnNotification", _value);
        new_class.x = _x;
        new_class.y = _y;
        new_class.z = _z;
        return new_class;
    },
};
 
var TestRecipient =
{
    new: function(_ident)
    {
        var new_class = Recipient.new(_ident);
console.log(new_class);
        new_class.count = 0;
        new_class.Receive = function(notification)
        {
            if (notification.Type == "TestNotification")
            {
                this.count = this.count + 1;
                return Transmitter.ReceiptStatus_OK;
            }
            return Transmitter.ReceiptStatus_NotProcessed;
        };
        return new_class;
    },
};
 
var TestRadarRecipient =
{
    new: function(_ident)
    {
        var new_class = Recipient.new(_ident);
        new_class.Receive = function(notification)
        {
            if (notification.Type == "RadarReturnNotification")
            {
                print(" :: Test recipient ",this.Ident, " recv:",notification.Type," ",notification.Value);
                print(" ::  ",notification.x, " ", notification.y, " ", notification.z);
                return Transmitter.ReceiptStatus_OK;
            }
            return Transmitter.ReceiptStatus_NotProcessed;
        };
        return new_class;
    },
};
 
function PerformTest(tid, t)
{
    if (t())
    {
        TestSuccessCount = TestSuccessCount + 1;
        print("  Test [Pass] :",tid);
    }
    else
    {
        TestFailCount = TestFailCount + 1;
        print("  Test [Fail] :",tid);
    }
}
 
var tt = TestRecipient.new("tt recipient");
var tt1 = TestRecipient.new("tt1 recipient1");
var tt3 = TestRecipient.new("tt3 recipient3");
var tt2 = TestRadarRecipient.new("tt2: Radar Test recipient2");
 
PerformTest("Create Notification",
            function ()
            {
                var tn = TestNotification.new("Test notification");
                return tn.Type == "TestNotification" && tn.Value == "Test notification";
            });
 
PerformTest("Register tt",
            function ()
            {
                GlobalTransmitter.Register(tt);
                return GlobalTransmitter.RecipientCount() == 1;
            });
PerformTest("Register tt1",
            function ()
            {
                GlobalTransmitter.Register(tt1);
                return GlobalTransmitter.RecipientCount() == 2;
            });
PerformTest("Register tt2",
            function ()
            {
                GlobalTransmitter.Register(tt2);
                return GlobalTransmitter.RecipientCount() == 3;
            });
PerformTest("Register tt3",
            function ()
            {
                GlobalTransmitter.Register(tt3);
                return GlobalTransmitter.RecipientCount() == 4;
            });
 
PerformTest("Notify",
            function ()
            {
                var rv = GlobalTransmitter.NotifyAll(TestNotification.new("Test notification"));
                return !Transmitter.IsFailed(rv) && rv != Transmitter.ReceiptStatus_NotProcessed && tt.count == 1;
            });
 
PerformTest("DeRegister tt1",
            function ()
            {
                GlobalTransmitter.DeRegister(tt1);
                return GlobalTransmitter.RecipientCount() == 3;
            });
 
tt1_count = tt1.count;
PerformTest("NotifyAfterDeregister",
            function ()
            {
                GlobalTransmitter.NotifyAll(TestNotification.new("Test notification"));
                return tt1.count == tt1_count;
            });
 
tt.Active = 0;
tt_count = tt.count;
 
PerformTest("Recipient.Active",
            function ()
            {
                var rv = GlobalTransmitter.NotifyAll(TestNotification.new("Test notification"));
                return !Transmitter.IsFailed(rv) && rv != Transmitter.ReceiptStatus_NotProcessed && tt.count == tt_count;
            });
 
 
PerformTest("Test Not Processed Notification",
            function ()
            {
                var rv = GlobalTransmitter.NotifyAll(TestNotProcessedNotification.new("Not Processed"));
                return rv == Transmitter.ReceiptStatus_NotProcessed;
            });
 
 
GlobalTransmitter.NotifyAll(RadarReturnNotification.new("Radar notification", "x0","y0","z0"));
 
if (!TestFailCount)
    print("Emesary: All ",TestSuccessCount," tests passed\n");
else
    print("Emesary: ERROR: Tests completed: ",TestFailCount," failed && ",TestSuccessCount," passed\n");
 
 
 
</syntaxhighlight>
 
== Related ==
== Related ==
* http://chateau-logic.com/content/emesary-multiplayer-bridge-flightgear
* http://chateau-logic.com/content/emesary-multiplayer-bridge-flightgear

Navigation menu