Skip to content

Repository files navigation

Addon

versionMaintenanceMITdepsizeKnown VulnerabilitiesBuild Status

This package provide the foundation to build Addons that will rely and work with the Core. Addon is just a container that will help you as a developer.

slimio

Scheduler is a external SlimIO Package. If you want to know more about it, follow this link.

Requirements

Getting Started

This package is available in the Node Package Repository and can be easily installed with npm or yarn.

$ npm i @slimio/addon
# or
$ yarn add @slimio/addon

👀 For a guide on how create/setup a first addon, please check available documentations in our Governance repository.

Usage example

A sample cpu addon.

importAddonfrom"@slimio/addon";// Create addonconstCPU=newAddon("cpu");// Register a callbackasyncfunctionsayHello(header,name=header.from){console.log(`hello ${name}`);}CPU.registerCallback(sayHello);// Catch start event!CPU.on("start",async()=>{console.log("cpu addon started!");// Execute local callbackawaitCPU.executeCallback("say_hello",void0,"thomas");// stdout "hello thomas";// Tell the core that your addon is ready!awaitCPU.ready();});// Export addon for SlimIO Core.exportdefaultCPU;

You might find it useful to read the source codes of our other addons, let us give you some nice links:

name (& link)Kinddescription
cpu-addonMetrologyRetrieve CPU metrics (cool to understood how works Entities and Metrics cards)
PrismCustomDistribution Server (An addon that deal with Stream and very specific behaviors)
AlertingBuilt-inManage alerting of the product (Deal with events observables and alarms)
GateBuilt-inThe core extension (Nothing special, just simple callbacks here)

Available events and life cycle

Addon is extended with a SlimIO Safe EventEmitter. Six kinds of events can be triggered:

eventdescription
startWhen the core ask the addon to start
stopWhen the core ask the addon to stop
awakeWhen the addon is ready to awake (all locks are ok)
sleepWhen a linked locked addon has been detected as stopped by the core
readyWhen the developer trigger ready() method to tell the Core that the addon is Ready for events
errorWhen a error occur in one of the EventEmitter listener

An addon have different given state during his life (started, awaken and ready). An addon is started when the core has recognized its existence and that it has been loaded successfully. The state ready have to be triggered by the developer itself in the start or awake event depending the need.

An addon wake up when all its dependencies are ready. A dependency can be added with the lockOn() method.

constmyAddon=newAddon("test").lockOn("events");myAddon.on("awake",async()=>{// Do something with events safely!constinfo=awaitmyAddon.sendOne("events.status");console.log(info);});

Interval & Scheduling

The Addon instanciate is own interval to execute Scheduled callbacks. The default interval time is setup at 500 milliseconds. To know how work the walk() method of Scheduler, please look at this documentation.

slimio

You can configure the default interval by editing static Addon variables (this is not recommanded):

Addon.MAIN_INTERVAL_MS=100;// 100ms

A concrete production example is to schedule a callback every 24 hours that start at midnight (but this callback can still be triggered manually by calling the callback).

show example
constmyAddon=newAddon("myAddon");letisCalled=false;asyncfunctionourJob(){isCalled=true;try{awaitnewPromise((resolve)=>setTimeout(resolve,10000));}finally{isCalled=false;}}asyncfunctionscheduledCallback(){if(isCalled){return{error: "Job already running!"}}ourJob().catch((err)=>myAddon.logger.writeLine(err));return{error: null};}myAddon.registerCallback(scheduledCallback).schedule(newScheduler({interval: 86400,startDate: newDate(newDate().setHours(24,0,0,0))}));

API

constructor (name: string, options?: Object)

Create a new Addon with a given name ! The name length must be more than two characters long. Available options are:

namedefaultValuedescription
version1.0.0Addon version
verbosefalseEnable addon verbose mode
descriptionEmpty stringAddon description
constmyAddon=newAddon("myAddon",{version: "0.1.0",verbose: true,description: "My Custom Addon!"});
ready(): Promise< boolean >

Flag the addon as ready for the core.

constmyAddon=newAddon("myAddon");myAddon.on("start",()=>{myAddon.ready();})
registerCallback (name: string | AsyncFunction, callback?: AsyncFunction): this

Register a new Addon callback. The callback should be an Asynchronous Function (Synchronous function will be rejected with a TypeError).

There is two ways to register a callback:

myAddon.registerCallback("callback_name",asyncfunction(){console.log("callbackName has been executed!");});

Please, be sure to avoid Anonymous function as much possible!

Or by passing the callback reference as the name (The function can't be anonymous, else it will throw an Error).

asyncfunctioncallback_name(){console.log("callbackName has been executed!");}myAddon.registerCallback(callback_name);

Callback name should be writted by following the snake_case convention snake_case !

executeCallback (name: string, ...args?: any[]): any

Execute a callback (It will return a Promise). The method can take infinity of arguments (they will be returned as normal arguments of the callback).

constmyAddon=newAddon("myAddon");myAddon.registerCallback(asyncfunctioncb_test(){return"hello world!";});myAddon.on("start",asyncfunction(){constret=awaitmyAddon.executeCallback("cb_test");console.log(ret);// stdout "hello world!"});
schedule (name: string | Scheduler, scheduler?: Scheduler): this

Schedule a callback execution interval. Use the package @slimio/scheduler to achieve a scheduler !

constScheduler=require("@slimio/scheduler");constAddon=require("@slimio/addon");constmyAddon=newAddon("myAddon");myAddon.registerCallback(asyncfunctionsayHelloEveryOneSecond(){console.log("hello world");});myAddon.schedule("sayHelloEveryOneSecond",newScheduler({interval: 1}));
setDeprecatedAlias(callbackName: string, alias: string[]): void

Setup a list of deprecated alias for a given callbackName. A NodeJS Warning will be throw if these alias are used (to warn developer/integrator to upgrade addon version).

constmyAddon=newAddon("myAddon");myAddon.registerCallback(asyncfunctionnew_test(){console.log("hello world!");});myAddon.setDeprecatedAlias("new_test",["old_test"]);
lockOn(addonName: string, rules?: Addon.Rules): this

Wait for an addon to be declared "ready" to awake local Addon. Rules argument is an Object described as follow:

exportinterfaceRules{startAfter?: boolean;lockCallback?: boolean;}

The default rule values are defined as: { startAfter = true, lockCallback = false }

  • startAfter: Ask our local addon to start after the given addonName.
  • lockCallback: Lock callback execution when our local addon is not awake.
constmyAddon=newAddon("myAddon").lockOn("events");myAddon.on("awake",()=>{console.log("events is ready!");myAddon.ready();});
of< T >(subject: string): ZenObservable.ObservableLike< T >

Subscribe to a given subject. Available "core" Subjects are:

interfaceSubjects{Addon: {readonlyReady: string;};Alarm: {readonlyOpen: string;readonlyUpdate: string;readonlyClose: string;};Metrics: {readonlyUpdate: string;}}

constmyAddon=newAddon("myAddon");myAddon.of(Addon.Subjects.Addon.Ready).subscribe((addonName)=>{console.log(`Addon with name ${addonName} is Ready !`);});
sendMessage< T >(target: string, options?: MessageOptions): ZenObservable.ObservableLike< T >

Send a lazy message to a given target formatted as following: addon.callback. The returned value is an Observable (package zen-observable).

constmyAddon=newAddon("myAddon");myAddon.on("start",function(){myAddon.sendMessage("cpu.status").subscribe(console.log);myAddon.ready();});

Available options are:

namedefault valuedescription
argsEmpty ArrayCallback arguments
noReturnfalseIf true, the method will return void 0 instead of a new Observable
timeout5000Timeout delay (before the hook expire)
sendOne< T >(target: string, options?: MessageOptions | any[]): Promise< T >

Send one lazy message to a given target formatted as following: addon.callback. The returned value is a Promise (Use sendMessage under the hood).

constmyAddon=newAddon("myAddon");myAddon.on("start",asyncfunction(){constaddons=awaitmyAddon.sendOne("gate.list_addons");console.log(addons);myAddon.ready();});

Available options are the same as sendMessage(). If options is an Array, the message options will be constructed as follow

{ args: [] }
registerInterval(callback: () => any | Promise< any >, ms?: number): string

Register a driftless timer interval that will be managed by the Addon itself. These intervals are only executed when the addon is awake. These functions (intervals) are protected against UnhandledPromiseRejection (so any errors will not lead the process to exit).

Intervals are erased when the stop event is triggered to avoid excessive use of memory (So think to register these intervals in the start event).

constmyAddon=newAddon("myAddon").lockOn("otherAddon");asyncfunctionmyInterval(){console.log("Hey ! I'm awake and will be executed every 5 seconds");}myAddon.on("start",()=>{myAddon.registerInterval(myInterval,5000);});

The method registerInterval return a unique id which can be used to retrieve the original Node.js timer etc...

constuid=myAddon.registerInterval(myInterval,5000);const{ ms, callback, nodeTimer }=myAddon.intervals.get(uid);nodeTimer.unref()

Static method

isAddon(obj: any): boolean

Detect if obj is an Addon (use a Symbol under the hood).

constmyAddon=newAddon("myAddon");console.log(Addon.isAddon(myAddon));// true

Streaming Communication

SlimIO Callback support NodeJS Write Streams. Take the following example:

conststreamAddon=newAddon("streamAddon");streamAddon.registerCallback(asyncfunctionstream_com(){constWStream=newAddon.Stream();setTimeout(()=>{WStream.write("msg1");},100);setTimeout(()=>{WStream.write("msg2");WStream.end();},200);returnWStream;});module.exports=streamAddon;

And now if we call this callback from an another Addon:

constmyAddon=newAddon("myAddon").lockOn("streamAddon");myAddon.on("awake",async()=>{myAddon.sendMessage("streamAddon.stream_com").subscribe((message)=>console.log(message),()=>console.log("Stream completed!"))awaitmyAddon.ready();});

Dependencies

NameRefactoringSecurity RiskUsage
@slimio/isMinorLowType checker
@slimio/loggerMinorLowSonic Logger with low overhead for SlimIO
@slimio/safe-emitter⚠️MajorMediumSafe emitter
@slimio/scheduler⚠️MajorLowAddon Scheduler
@slimio/timerMinorLowDriftless Interval Timer
is-snake-caseMinorLowSnake case checker
uuidMinorLowSimple, fast generation of RFC4122 UUIDS.
zen-observableMinorLowObservable Implementation

License

MIT

About

SlimIO Addon container

Resources

Contributing

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages