antinite
Antinite is a zero dependency lightweight nano-services framework inside one node process.
Raison d'être:
Its will be necessary to have sort of Seneca or Studio.js framework inside one process (without numbers of process and costly interprocess interaction) AND with some kind of ACL-based access control. Also system should represent services interaction logs on demand.
Features:
- Layers (domains) to arrange services to logical groups
- Services with explicit dependencies and exported function
- Auto-resolving for all services dependencies
- Available auto-init resolved services
- Services request audit on demand
- Extract current system graph on demand
- Legacy helper for lazy refactoring
- Async service initialization
Install:
npm install antinite
Example:
Short diagram to explain long code example
// first service file aka 'foo_service' { // IMPORTANT - convented function name for service config return require: BarService: 'getBar' // this is external dependency export: execute: 'doFoo' // this action will exported as 'execute' type (all types - 'execute', 'write', 'read') options: // options for service injectRequire : true // inject require part to class itsels } { // always available require call let bar = this // call to remote service, convented function name // or with `options.injectRequire` = true let bars = thisBarService return ` and foo and ` }
// first layer file aka 'services_layer' const LAYER_NAME = 'service' // domain for services aka layerconst SERVICES = // services list name: 'FooService' // exported service name service: // service object acl: 711 // service rights (for system/layer/other) let layerObj = LAYER_NAME // register layerlayerObj // fulfill with services
// second service file aka 'bar_service' { return export: read: 'getBar' // this action will exported as 'read' type } { return 'its bar' }
// second layer file aka 'shared_layer' const LAYER_NAME = 'shared'const SERVICES = name: 'BarService' service: acl: 764 let layerObj = LAYER_NAMElayerObj
// main start point aka 'index' // load layers, in ANY orders let antiniteSys = 'mainSystem' // create system object to access any exported actions (system do 'require *', kind of)antiniteSys
Usage:
Antinite framework has some main parts - Layer
and System
and some helpers - Legacy
, Auditor
, Debugger
and AntiniteToolkit
.
Moreover antinite has service conception - any object, used in Layer
as service, MUST declare configuration with getServiceConfig
method and MAY declare initService
to initialise service after all requires will be resolved and MAY use this.doRequireCall()
to call other services - its will be injected at Layer
init.
Service
Antinite may use prepared object as service if it declare configuration. The are three reserved methods names getServiceConfig
, initService
and doRequireCall
.
Declare configuration
{ return require: BarService: 'getBar' export: execute: 'doFoo' options: injectRequire : true }
Service must declare public methods at 'export' part and used actions from another services in 'require' part.
Its may be some options for service, injectRequire
allow to call actions from another services as part of service class, for example:
// without injectionlet one = this// with injectionlet two = thisBarService
Its looks better and represents smooth code.
IMPORTANT! Injection throw error if object already have field with same name as required service.
Service initialization
// at service class constructor{ thisstorage = null // internal field of class}// and fill it when service resolve all requires { // IMPORTANT - convented function name for service init let bar = this // call to remote service, now its ready thisstorage = bar}
Also its available async initService
as callback or promise
{ // async callback-style }
{ // async promise-style return }
Service may declare initService
method at class to automatic execute it when all requires will be resolved but before all system will be ready.
IMPORTANT! do not change state of another services here, or hard to debug errors may accured here.
System startup
let antiniteSys = 'mainSystem' // create system object to access any exported actions (system do 'require *', kind of) antiniteSys
Main System object may set .onReady()
promise-style listener, or callback-style .onReady(cb)
.
IMPORTANT! This async style strictly must be used if async initService()
used!
Call required service
var res = this
Service may call other services by serviceName and actionName pair with any arguments, if destination service allow access.
IMPORTANT! Service may have 'group' or 'other' part of ACL in case of in same or in different layers with destination service is it.
IMPORTANT! At auto resolving process Antinite do call to first granted service action (at different layers may be services with some name and different access rights)
Layer
Antinite use layers (or domains) to arrange same services and separate different.
Create layer object
let layerObj = layerName
Create new named layer.
Add services to layer
layerObj
Add services list to layer
Services must be an array of object:
name : 'FooService' service : acl : 711 ...
IMPORTANT! Service must be an instance, not class.
System
Create system object
let antiniteSys = 'mainSystem'
Create Antinite System object with own access level.
IMPORTANT! System ACL always is 'system' (first digit).
Execute action
let res = antiniteSys
Do call to service action in particular layer with any arguments
Сheck is system are ready
antiniteSys
Check all system (in current node process) to ensure all 'required' actions available (exists AND allowed to callers), otherwise throw an error.
Get unready services list
antiniteSys
Return list of unready services. This method simplify unready service point.
Legacy
To simplify legacy code refactoring to Antinite nano-services may be used Legacy
helper
Get Legacy helper pointer
Legacy
helper join Layer
and service at one place. Class must represent getServiceConfig()
as ordinary service AND call to Legacy.register()
, as Layer
do it, for example at object constructor.
{ this } { Legacy } { return require: Logger: 'log' ConfigReader:'read' export: read: 'getStatus' }
At result services.LegacyService
was registered with getStatus
exported function.
Limitations! By design original Layers
must be unique, therefore all Layers
MUST be required before any legacy objects.
Nevertheless Legacy
object will be added to original layers or will be create new and Legacy
objects will be add until services names are unique.
Auditor
Get auditor pointer
Get Antinite Auditor pointer, not a object - due to optimization enhancements this system-wide (in current node process) item.
Its used to get inter-services interaction log.
Turn on/off audit
Auditor
Set system audit mode on(true) or off(false).
IMPORTANT! Due to optimization enhancements this system-wide (in current node process) flag.
Get audit log
Auditor
Get audit log.
Example:
Set audit log storage size
Auditor
Set auditor log storage size.
IMPORTANT! Due to optimization enhancements this system-wide (in current node process) flag.
Debugger
Get debugger pointer
Get Antinite Debugger pointer, not a object - due to optimization enhancements this system-wide (in current node process) item.
Its used to get internal Antinite log to help maintenance services
Turn on/off debug
Debugger
Set system debug mode on(true) or off(false).
IMPORTANT! Due to optimization enhancements this system-wide (in current node process) flag.
IMPORTANT! To get all messages for 'require' resolving turn debugger on before import layers at main index.
Get debug log
Debugger
Get debug log.
Example:
Set debug log storage size
Debugger
Set debugger log storage size.
IMPORTANT! Due to optimization enhancements this system-wide (in current node process) flag.
AntiniteToolkit
Get toolkit pointer
This service part for develop and debug
Get current system graph
AntiniteToolkit
Return current system graph like this
This data may be used to visualize system, see online example, created by Antinite Visual Toolkit.
Data structure is simply - layers (or domain) at top, then services and its configuration. The isReady
flag indicate layer or service successfully resolve all requests. The resolved
field at service require section point to layer, where action will be resolved.
General Notes:
ACL bits
x | w | wx | r | rx | rw | rwx | |
---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
ACL digit position
first | second | third |
---|---|---|
system | group | other |
'system' - access level for system calls (system call service 'Foo' at layer 'Bazz')
'group' - access level for calls in some layer (service 'Foo' and 'Bar' at layer 'Bazz')
'other' - access level for calls from other layers (service 'Foo' at layer 'Bazz' and service 'Qux' at layer 'Waldo')
ACL example
741
- system has read, write and execute rights, services in some layer - read only, services from other layers - execute only