20,741
edits
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 |