Event System
Gofer Engine's Event System's library package has been named handelse.
Händelse is the Swedish word for event.
This library is designed to be used as a standalone event system library package if so desired.
import eventSystemManager from '@gofer-engine/handelse';
// ...
The default export of the library is an initialized class of the
EventSystemManager. Since this is the default import, you can shorten the name
to your liking:
import handelse from '@gofer-engine/handelse';
// ...
If instead you wish to initialize or extend the EventSystemManager class
yourself, you can import just the class and initialize your own manager.
import { EventSystemManager } from '@gofer-engine/handelse';
const manager = new EventSystemManager(["custom-reserved-handler"]);
// ...
Global vs. Local Handlers
The handelse library provides both named global event handlers, and unnamed local event handlers. Named global event handlers can be later retrieved outside of the current scope while local event handlers only live within their current scope.
Create a Local Handler
To create a local event handler, use the createLocal method:
import eventSystemManager from '@gofer-engine/handelse';
// ...
const localHandler = eventSystemManager.createLocal();
// ...
Alternatively you can use these aliases for the createLocal method: local,
createInstance, instance.
Create a Global Handler
To create a global event handler, use the createGlobal method:
import eventSystemManager from '@gofer-engine/handelse';
eventSystemManager.createGlobal('example-global-event-handler');
// ...
Alternatively you can use these aliases for the createGlobal method: create,
global.
Get a Global Handler
Global Event Handlers can be later retrieved by their referenced handle.
import eventSystemManager from '@gofer-engine/handelse';
// ...
const exampleGlobalEventHandler = eventSystemManager.get(
'example-global-event-handler'
);
// ...
For many use cases, it will be uneccessary to retrieve the handler to perform
routine tasks such as publishing or subscribing to an event handler as these
actions can be performed from the eventSystemManager class by passing the
handler name.
As local event handlers are not referencable by name within the manager after
creation, the get, sub, pub, unsub and delete methods only support
global event handlers. See The Event System
Manager.
Event Handling
After creating either a local or global event handler, you can use the handler the following ways:
Subscribing
The sub methos allows adding a subscriber to an event handler. A subscriber is
simply a promisable function that returns a boolean. If the subscriber
successfully handled the event, then the return should be true. If the
subscriber rejected the event, then the return should be false.
// ...
const localSubId = localHandler.sub((event) => {
console.log(event);
return true;
});
// ...
The return of the sub method returns the subscriber id. This id can be later
used to unsubscribe this particular subscription.
Alternatively, you could use any one of these aliases for the sub method:
subscribe, on, do, start, or listen.
Publishing
The pub method provides the ability to publish an event to all subscribers.
// ...
localHandler.pub('Hello World!');
// ...
The pub method returns a promise object, mapping each subscriber's id to it's
acceptance of the event.
Alternatively, you could use any one of these aliases for the pub
method: publish, go, emit, broadcast, or signal
Unsubscribing
The unsub method allows for active subscribers to be removed from the current
handler. The input requires the subscriber identifier which is returned when
adding the subscriber. See Subscribing
// ...
localHandler.unsub(localSubId);
// ...
Alternatively, you could use any of of these aliases for the unsub method:
unsubscribe, off, remove, stop, or deafen
You can bulk unsubscribe all subscribers using the removeAll method.
// ...
exampleGlobalEventHandler.removeAll();
// ...
The Event System Manager
Aside from creating event handlers, the Event System Manager provided methods for directly interacting with global event handlers.
Global Subscribing
The sub method works identical to the sub method of the event handler
class, with the addition of the handler name as the first
argument.
import eventSystemManager from '@gofer-engine/handelse';
// ...
const subId_1 = eventSystemManager.sub('example-global-event-handler', (event) => {
console.log(event);
return true;
});
// ...
Alternatively, you could use any one of these aliases for the sub method:
subscribe, on, do, start, or listen.
Global Publishing
The pub method works identical to the pub method of the event handler
class, with the addition of the handler name as the first
argument.
import eventSystemManager from '@gofer-engine/handelse';
// ...
eventSystemManager.pub('example-global-event-handler', 'Hello World!');
// ...
Alternatively, you could use any one of these aliases for the pub
method: publish, go, emit, broadcast, or signal
Global Unsubscribing
The unsub method works identical to the unsub method of the event handler
class, with the addition of the handler name as the first
argument.
import eventSystemManager from '@gofer-engine/handelse';
// ...
eventSystemManager.unsub('example-global-event-handler', subId_1);
// ...
Alternatively, you could use any of of these aliases for the unsub method:
unsubscribe, off, remove, stop, or deafen
You can bulk unsubscribe all subscribers using the removeAllSubs method. This
method works similar to the removeAll method of the handler class
// ...
eventSystemManager.removeAllSubs('example-global-event-handler');
// ...
Deleting Handlers
The delete method provides the capability for removing Global Event Handlers.
Local Event Handlers do not have a delete method as they naturally live within
their scope and are natively garbage collected by the environment. Global Event
Handlers live forever within the scope of the running process. So when they are
no longer being used, it would be wise to delete the global event handlers to
allow native garbage collection processes.
// ...
eventSystemManager.delete('example-global-event-handler');
// ...
The manager also provides the clear method for removing all global event
handlers.
// ...
eventSystemManager.clear();
You cannot delete the reserved _ALL_ global event handler. When clearning all
global event handlers using the clear() method, the reserved _ALL_ event
handler will be reattached.
Typing Event Handlers
If you are using TypeScript in your project, which we highly recommend, then you
can pass in generic types to validate event types upon compiling. These generics
are available to use when creating local or global event handlers, and can be
used to strongly type global handlers retrived using the get method.
TypeScript typing can only be used while compiling and not during runtime. For
this purpose, we have included the eventType option parameter to help do basic
type checking during runtime using the typeof syntax. This will throw errors
during runtime if the typeof event does not match the options.eventType if
it is not undefined.
You can do additional type checking in your subscriber functions and rejecting
malformed data. This eventType option runs the check before hitting
subscribers.
// ...
eventSystemManager.global<'foo'|'bar'>('typed-handler', { eventType: 'string' });
const typedHandler = eventSystemManager.get<'foo'|'bar'>('typed-handler');
typedHandler.sub((event) => {
// @ts-expect-error - event is typed as 'foo'|'bar' and not `string`
if (event === 'baz') {
console.log(event);
}
return true;
});
// @ts-expect-error - event is typed as 'foo'|'bar' and not `string`
typedHandler.pub('baz');
// ...
If you manually coerce typescript types in your publisher, then your subscribers may receive events of an unexpected type. It is always recommended to add additional sanitization and data validation processes before sending data to systems susceptable to injection vulnerabilities.
Advanced Options
With the available options object, you can do the following advanced workflows:
- Subscribe to Global Event Handlers not already existing with the
createIfNotExistsoption set totrue - Publish to Global Event Handlers not already existing with the
createIfNotExistsoption set totrue - Prevent errors of creating Global Event Handlers already created with the
getIfAlreadyCreatedoption set totrue
// ...
eventSystemManager.sub(
'new-handler',
e => Boolean(console.log(e)),
{ createIfNotExists: true },
);
eventSystemManager.global('new-handler', { getIfAlreadyCreated: true });
// ...
Remember that global handlers should be globally unique within the running
process. It might be beneficial to use a custom prefix for handlers that you
manage if your are using handelse as a library within your application. In Gofer
Engine, we prefix most global handlers with gofer: and within channel contexts
include the channel id as well.
The _ALL_ Event Handler
Handelse creates a global handler named _ALL_ that cannot be removed or
published to directly. This handler is automatically subscribed to all other
event handlers. This allows you to listen globally to all events. The Event
System Manager provides the method subAll and aliases all, subscribeAll,
onAll, doAll, startAll, or listenAll to add subscriber functions to this
_ALL_ global event handler.
This reserved handler can be used like any other global event handler with the exception of being able to directly publish to this handler.
Gofer Engine LOGGER Handle
Gofer Engine adds an additional global handler named LOGGER. Subscribing to
this event handler, you can setup a custom log receiver in additional to or
instead of the default console.log handler.
See Logging for more information.