HaxEDA
Haxe-EDA implementation.
Install
haxelib install haxeda
Write your Tests
Use haxeda-test
to write your Tests. There is also information
about how to write them.
Write your business logic
First, lookup how to write some tests and create your first tastcase. Some functions created for the tests will be used in the business logic as well.
1. Create, bind listeners and start the EventEngine ate the application start
In the main method, you can instance the EventEngine, Bind all listeners to it and start the event Engine:
import haxeda.EventEngine;
class Main {
public static function main() {
var eventEngine = new EventEngine();
var registerer = new MyEventEngineRegisterer();
registerer.registerToEventEngine(eventEngine);
eventEngine.start(RunTilNoneWaiting);
}
}
First, get the EventEngineRegisterer
you have already created in the tests. Then let it register to the new created EventEngine
using registerToEventEngine
. Because you haven't passed the isTest
-flag, it will be default to false.
During creation of the EventEngine
(new EventEngine(eventSaver)
), you can pass a haxeda.persistent.EventSaver
. It will store all you events and you can use it to restore the last state. For example you can use the haxeda.persistent.DefaultEventSaver
, that one will save everything into a json-file. If one is passed, it will be use to save the Events, so no Data is lost after Shutdown. Adding it to the EventEngine
will automaticlly restore everything.
As last step, just call start
on the EventEngine. This will trigger the Event ApplicationStarted
as well. The parameter tells, when the if the EventEngine
should terminate:
- RunTilKillEvent
runs until the event haxeda.events.ApplicationExit
was send - RunTilNoneWaiting
runs until every event were processed (if some Events were in Status Waiting
, the engine keeps running)
- RunTilReturns
runs until every listener got called (its possible, that the engine will terminate, but the are still some events in Status Waiting
).
2. Create Listeners with @listener
To create listener functions, you have create classes the implements the EventListener
interface. Inside the Class you can create listener functions by adding @listener
to it.
The function has to expect only one parameter as the event and return a
EventProcessingResult
:
- Success
indicates, that the event was processed without anny errors
- StopProcessing(retryInMs)
indicates, that this class should stop processing and reprocess the same event in retryInMs
.
- WithError(errorString)
stops processing this and further events in the same class. Its currently only for future use, when unlocking will be implemented
To listen to events it has to call the method
registerToEventEngine
, it will be generated when implementing haxeda.EventListener
:
class SomeListerner implements haxeda.EventListener{
private var eventEngine: haxeda.EventEngine;
public function new(eventEngine: haxeda.EventEngine){
this.eventEngine = eventEngine;
this.registerToEventEngine(eventEngine);
}
@listener
public function onGettingSomeEvent(ev:SomeEvent) : haxeda.EventListener.EventProcessingResult {
//Do some processing
this.eventEngine.triggerEvent(new SomeEventDone());
return Success;
}
}
Defining the Events
The events has to implement the Event
interface, for example see the simple
haxeda.events.ApplicationStarted
event:
package haxeda.events;
class ApplicationStarted implements haxeda.Event {
public function new(){}
}
Autoupdate Data with events
You can use the @update
to autoupdate data from any event:
class SomeListerner implements haxeda.EventListener{
@update var someGlobalValue : String = "";
//register to eventengine
}
class UpdateGlobalData implements haxeda.Event {
@update var someGlobalValue : String;
public function new(valueToSend : String){
this.someGlobalValue = valueToSend;
}
}
By sending a UpdateGlobalData
all registered haxeda.EventListener
's variables of type
String named someGlobalValue
with @update
will receive the data, no listener needs
to be implemented for this.
You can also keep track of an Array of Objects. For example we need some personal data of different users.
We can create a PersonListener:
struct Person {
firstName: String,
secoundName: String,
familyName: String,
};
struct FullPerson { > Person, tel: String };
class DataDeleteKeyListerner implements EventListener{
@keyTable("person") var email : String = "";
@keyTable("person") var personName : { firstName: String, familyName: String };
@keyTable("person") var person : Person;
@keyTable("person") var fullperson : FullPerson;
@keyTable("person") var mailperson : { > Person, email: String };
//register to eventengine
}
Now lets create an event, that updates the name and the email:
class UpdateKeyValueData implements haxeda.Event {
@update var firstName : String;
@update var email : String;
@key var person : String;
public function new(personId: String, name: String, mail: String){
this.person = personId;
this.firstName = name;
this.mail = mail;
}
}
On sending this Event, you update
- email[ev.person] = ev.mail
- mailperson[ev.person].email = ev.mail
- personName[ev.person].firstName = ev.firstName
- person[ev.person].firstName = ev.firstName
- fullperson[ev.person].firstName = ev.firstName
- mailperson[ev.person].firstName = ev.firstName
If the person doesn't exist, it will be created. To delete a person, you need the following Event:
class DeletePerson implements haxeda.Event {
@deleteKey var person : String;
public function new(personId: String){
this.person = personId;
}
}
@keyTable
variables of type T
can be accessed like any normal Map<String,T>
, in fact
it will be compiled into a Map<String,T>
.
Sending Events
You can send events by using the triggerEvent
method, see this example:
class SomeListener implements haxeda.EventListener{
private var eventEngine: haxeda.EventEngine;
public function new(eventEngine: haxeda.EventEngine){
this.eventEngine = eventEngine;
this.registerToEventEngine(eventEngine);
}
@listener
public function onDoSomeWork(someWork:DoSomeWork) : haxeda.EventListener.EventProcessingResult {
var result = this.doSomeWork(someWork);
this.eventEngine.triggerEvent(new WorkDone(result));
if(result){
return Success;
} else {
return StopProcessing(2000);
}
}
}
You don't have to send events from a listener, it can be send from any place you want.
Other methods to create listeners
You can also create a listener function without @listener
. It will not be bound to
the EventEngine
by calling this.registerToEventEngine(eventEngine);
. You still have
to call this.registerToEventEngine(eventEngine);
to auto update @update
or @keyTable
variables.
class SomeListerner implements haxeda.EventListener{
public function new(eventEngine: haxeda.EventEngine){
//call this.registerToEventEngine(eventEngine) and do other stuff
eventEngine.registerFunction(SomeEvent, this, onGettingSomeEvent);
}
public function onGettingSomeEvent(ev:SomeEvent) : haxeda.EventListener.EventProcessingResult {
//Do some processing
this.eventEngine.triggerEvent(new SomeEventDone());
return Success;
}
}
Also you can create a Listener for all events:
class SomeListerner implements haxeda.EventListener{
public function new(eventEngine: haxeda.EventEngine){
//call this.registerToEventEngine(eventEngine) and do other stuff
eventEngine.registerFunction(SomeEvent, this, onGettingSomeEvent);
}
public function onGettingSomeEvent(ev:SomeEvent) : haxeda.EventListener.EventProcessingResult {
//Do some processing
this.eventEngine.triggerEvent(new SomeEventDone());
return Success;
}
}
Register and Unregister Listeners
You can use eventEngine.registerFunction(Event, Listener, ListenerFun)
to register an Function to an Event or
eventEngine.removeFunction(Event, Listener, ListenerFun)
to remove the function.
The Parameters of eventEngine.removeFunction(Event, Listener, ListenerFun)
has to
have the same value like it was used on
eventEngine.registerFunction(Event, Listener, ListenerFun)
!
You can use eventEngine.registerListener(Listener)
to only update the variables and
eventEngine.removeListener(Listener)
to not update the variables nor call any ListenerFun.
TODOs:
-
API for undoing Events:
By using the History Data ist should be possible to undo events