Stability: 2 - Unstable
WARNING
This project is in active development and is not feature-complete yet, but is already mature enough.
The documentation of this specific implementation is not complete either.
FutoIn reference implementation
Reference implementation of:
FTN7: FutoIn Invoker Concept
Version: 1.4
FTN3: FutoIn Interface Definition
Version: 1.2
FTN5: FutoIn HTTP integration
Version: 1.2
FTN9: FutoIn Interface - AuditLog
Version: 1.0 (client)
FTN14: FutoIn Cache
Version: 1.0 (client)
Web Site
About
FutoIn Invoker is a peer which initiates a request - invokes a FutoIn interface method
as described in FTN3: FutoIn Interface Definition.
It is not necessary a client - e.g. server may initiate request for event delivery to client.
The method can be implemented locally or remotely - it is transparent to invoking code.
A similar concept can be found in CORBA and other more heavy request brokers.
Strict FutoIn interface (iface) definition and transport protocol is defined in FTN3 spec mentioned above.
As it is based on JSON, both client and server can be implemented in a few minutes almost in
any technology. However, Invoker and Executor concept provide significant benefits for
efficiency, reliability and error control.
The core of invoker is CCM - Connection and Credentials Manager.
It has the following advantages:
- A single place to configure & hold sensitive data (like credentials)
- Transparent connection management (no need for special connect/request/response/disconnect logic)
- Efficient use of communications (keep-alive, persistent WebSockets channels,
channel-based instead of message-based security, etc.)
- Inversion of Control / Dependency Injection - implementations are referenced by
static names like "mymodule.some.service" in code. The rest is hidden in CCM configuration.
- Easy HMAC-based message signature and user authentication
- Security enforcement
The primary communication channel is WebSockets. Large raw data upload and download
is also supported through automatic fallback to HTTP(S).
SimpleCCM - a light version without heavy processing of iface definition (ideal for browser)
AdvancedCCM - full featured CCM (extends SimpleCCM)
Communication methods:
- HTTP/HTTPS - remote calls
- WS/WSS - WebSockets remote calls with bi-directional sockets
- HTML5 Web Messaging - same- and cross-origin local calls inside Browser through window.postMessage() API
- Same Process - optimized for single instance deployment
Note: Invoker and Executor are platform/technology-neutral concepts. The implementation
is already available in JS and PHP. Hopefully, others are upcoming
Installation for Node.js
Command line:
$ npm install futoin-invoker --save
Installation for Browser
$ bower install futoin-invoker --save
Please note that browser build is available under in dist/ folder in sources generated
with pure-sjc. It depends on
lodash.
Note: there are the following globals available:
- SimpleCCM - global reference to futoin-invoker.SimpleCCM class
- AdvancedCCM - global reference to futoin-invoker.AdvancedCCM class
- futoin.Invoker - global reference to futoin-invoker module
Examples
NOTE: more complex examples should be found in (futoin-executor)[https://github.com/futoin/core-js-ri-executor/]
Call remote function with SimpleCCM
var async_steps = require( 'futoin-asyncsteps' );
var invoker = require( 'futoin-invoker' );
var ccm = new invoker.SimpleCCM();
async_steps()
.add(
function( as ){
ccm.register( as, 'localone', 'some.iface:1.0', 'https://localhost/some/path' );
ccm.register( as, 'localtwo', 'other.iface:1.0', 'https://localhost/some/path' );
as.add( function( as ){
var localone = ccm.iface( 'localone' );
var localtwo = ccm.iface( 'localtwo' );
localone.call( as, 'somefunc', {
arg1 : 1,
arg2 : 'abc',
arg3 : true,
} );
as.add( function( as, res ){
console.log( res.result1, res.result2 );
} );
} );
},
function( as, err )
{
console.log( err + ': ' + as.state.error_info );
console.log( as.state.last_exception.stack );
}
)
.execute();
Call remote function with AdvancedCCM
var async_steps = require( 'futoin-asyncsteps' );
var invoker = require( 'futoin-invoker' );
var some_iface_v1_0 = {
"iface" : "some.iface",
"version" : "1.0",
"ftn3rev" : "1.1",
"funcs" : {
"get" : {
"params" : {
"arg1" : {
"type" : "integer"
},
"arg2" : {
"type" : "string"
},
"arg3" : {
"type" : "boolean"
}
},
"result" : {
"result1" : {
"type" : "number"
},
"result2" : {
"type" : "any"
}
},
"throws" : [
"MyError"
]
}
},
"requires" : [
"SecureChannel",
"AllowAnonymous"
]
};
var ccm = new invoker.AdvancedCCM({
specDirs : [ __dirname + '/specs', some_iface_v1_0 ]
});
async_steps()
.add(
function( as ){
ccm.register( as, 'localone', 'some.iface:1.0', 'https://localhost/some/path' );
ccm.register( as, 'localtwo', 'other.iface:1.0', 'https://localhost/some/path' );
as.add( function( as ){
var localone = ccm.iface( 'localone' );
var localtwo = ccm.iface( 'localtwo' );
localone.call( as, 'somefunc', {
arg1 : 1,
arg2 : 'abc',
arg3 : true,
} );
as.add( function( as, res ){
console.log( res.result1, res.result2 );
} );
} );
},
function( as, err )
{
console.log( err + ': ' + as.state.error_info );
console.log( as.state.last_exception.stack );
}
)
.execute();
API documentation
The concept is described in FutoIn specification: FTN7: Interface Invoker Concept v1.x
#Index
Modules
Classes
- class: CacheFace
- class: SimpleCCM
- class: AdvancedCCM
- class: FutoInError
- class: LogFace
- class: InterfaceInfo
- class: NativeIface
- class: SpecTools
- new SpecTools()
- SpecTools.loadIface(as, info, specdirs)
- SpecTools.parseIface(as, info, specdirs, raw_spec)
- SpecTools.checkConsistency(as, info)
- SpecTools.checkType(info, type, val)
- SpecTools.checkParameterType(info, funcname, varname, value)
- SpecTools.checkResultType(as, info, funcname, varname, value)
- SpecTools.genHMAC(as, info, ftnreq)
- const: SpecTools.standard_errors
Members
#futoin-invoker
#class: CacheFace
Members
##new CacheFace()
Cache Native interface
Register with CacheFace.register()
NOTE: it is not directly available in Invoker module
interface, include separately
##CacheFace.ifacespec
Embedded spec for FutoIn CacheFace
##CacheFace.register()
AuditLog Native interface registration helper
##cacheFace.getOrSet(as, key_prefix, callable, params, ttl_ms)
Get or Set cached value
NOTE: the actual cache key is formed with concatenation of key_prefix and join
of params values
Params
- as
AsyncSteps
- key_prefix
string
- unique key prefix - callable
function
- func( as, params.. ) - a callable
which is called to generated value on cache miss - params
Array
- parameters to be passed to callable - ttl_ms
integer
- time to live in ms to use, if value is set on cache miss
#class: SimpleCCM
Members
##new SimpleCCM([options])
Simple CCM - Reference Implementation
Base Connection and Credentials Manager with limited error control
Params
- [options]
object
- map of options (see OPT_* consts)
##SimpleCCM.OPT_COMM_CONFIG_CB
Communication configuration callback( type, specific-args )
##simpleCCM.register(as, name, ifacever, endpoint, [credentials], [options])
Register standard MasterService end-point (adds steps to as)
Params
- as
AsyncSteps
- AsyncSteps instance as registration may be waiting for external resources - name
string
- unique identifier in scope of CCM instance - ifacever
string
- interface identifier and its version separated by colon - endpoint
string
- URI
OR any other resource identifier of function( ccmimpl, info )
returning iface implementing peer, accepted by CCM implementation
OR instance of Executor - [credentials]
string
- optional, authentication credentials:
'master' - enable MasterService authentication logic (Advanced CCM only)
'{user}:{clear-text-password}' - send as is in the 'sec' section
NOTE: some more reserved words and/or patterns can appear in the future - [options]
object
- fine tune global CCM options per endpoint
##simpleCCM.iface(name)
Get native interface wrapper for invocation of iface methods
Params
- name
string
- see register()
Returns: NativeInterface
- - native interface
##simpleCCM.unRegister(name)
Unregister previously registered interface (should not be used, unless really needed)
Params
- name
string
- see register()
##simpleCCM.defense()
Shortcut to iface( "#defense" )
##simpleCCM.log()
Returns extended API interface as defined in FTN9 IF AuditLogService
Returns: object
##simpleCCM.cache()
Returns extended API interface as defined in [FTN14 Cache][]
Returns: object
##simpleCCM.assertIface(name, ifacever)
Assert that interface registered by name matches major version and minor is not less than required.
This function must generate fatal error and forbid any further execution
Params
- name
string
- unique identifier in scope of CCM instance - ifacever
string
- interface identifier and its version separated by colon
##simpleCCM.alias(name, alias)
Alias interface name with another name
Params
- name
string
- unique identifier in scope of CCM instance - alias
string
- alternative name for registered interface
##simpleCCM.close()
Shutdown CCM (close all active comms)
##const: SimpleCCM.OPT_CALL_TIMEOUT_MS
Overall call timeout (int)
##const: SimpleCCM.OPT_PROD_MODE
Production mode - disables some checks without compomising security
##const: SimpleCCM.OPT_SPEC_DIRS
Client-side executor for bi-directional communication channels
##const: SimpleCCM.OPT_TARGET_ORIGIN
browser-only. Origin of target for window.postMessage()
##const: SimpleCCM.OPT_RETRY_COUNT
How many times to retry the call on CommError
##const: SimpleCCM.OPT_HMAC_KEY
Base64 encoded key for HMAC generation
##const: SimpleCCM.OPT_HMAC_ALGO
Hash algorithm for HMAC generation:
MD5(default), SHA224, SHA256, SHA384, SHA256
##const: SimpleCCM.SAFE_PAYLOAD_LIMIT
Maximum FutoIn message payload size (not related to raw data)
##const: SimpleCCM.SVC_RESOLVER
Runtime iface resolution v1.x
##const: SimpleCCM.SVC_AUTH
AuthService v1.x
##const: SimpleCCM.SVC_DEFENSE
Defense system v1.x
##const: SimpleCCM.SVC_ACL
Access Control system v1.x
##const: SimpleCCM.SVC_LOG
Audit Logging v1.x
##const: SimpleCCM.SVC_CACHE_
cache v1.x iface name prefix
#class: AdvancedCCM
Members
##new AdvancedCCM()
Advanced CCM - Reference Implementation
##const: AdvancedCCM.OPT_SPEC_DIRS
Search dirs for spec definition or spec instance directly
#class: FutoInError
Members
##new FutoInError()
Easy access of futoin-asyncsteps.FutoInError errors, which may be extended in the future
#class: LogFace
Members
##new LogFace()
AuditLog Native interface
Register with LogFace.register().
NOTE: it is not directly available Invoker module
interface, include separately
##LogFace.ifacespec
Embedded spec for FutoIn LogFace
##LogFace.register()
AuditLog Native interface registration helper
##logFace.msg(lvl, txt)
Log message
Params
- lvl
string
- debug|info|warn|error|security - txt
string
- message to log
##logFace.msg(lvl, txt, data)
Log message
Params
- lvl
string
- debug|info|warn|error|security - txt
string
- message to log - data
string
- raw data
##logFace.debug(txt)
Log message in debug level
Params
- txt
string
- message to log
##logFace.info(txt)
Log message in info level
Params
- txt
string
- message to log
##logFace.warn(txt)
Log message in warn level
Params
- txt
string
- message to log
##logFace.error(txt)
Log message in error level
Params
- txt
string
- message to log
##logFace.security(txt)
Log message in security level
Params
- txt
string
- message to log
##const: LogFace.LVL_DEBUG
Debug log level
##const: LogFace.LVL_INFO
Info log level
##const: LogFace.LVL_WARN
Warn log level
##const: LogFace.LVL_ERROR
Error log level
##const: LogFace.LVL_SECURITY
Security log level
#class: InterfaceInfo
Members
##new InterfaceInfo()
FutoIn interface info
##interfaceInfo.name()
Get FutoIn interface type
Returns: string
##interfaceInfo.version()
Get FutoIn interface version
Returns: string
##interfaceInfo.inherits()
Get list of inherited interfaces starting from the most derived, may be null
Returns: object
##interfaceInfo.funcs()
Get list of available functions, may be null
Returns: object
##interfaceInfo.constraints()
Get list of interface constraints, may be null
Returns: object
#class: NativeIface
Members
##new NativeIface()
Native Interface for FutoIn ifaces
##nativeIface.call(as, name, params, upload_data, [download_stream], [timeout])
Generic FutoIn function call interface
Result is passed through AsyncSteps.success() as a map.
Params
- as
AsyncSteps
- AsyncSteps object - name
string
- FutoIn iface function name - params
object
- map of func parameters - upload_data
string
| stream.Readable
- raw upload data or input stram - [download_stream]
stream.Writable
- output stream for raw download data - [timeout]
int
- if provided, overrides the default. <=0 - disables timeout
##nativeIface.call()
Get interface info
Returns: object
##nativeIface.bindDerivedKey()
Results with DerivedKeyAccessor through as.success()
#class: SpecTools
Members
- class: SpecTools
- new SpecTools()
- SpecTools.loadIface(as, info, specdirs)
- SpecTools.parseIface(as, info, specdirs, raw_spec)
- SpecTools.checkConsistency(as, info)
- SpecTools.checkType(info, type, val)
- SpecTools.checkParameterType(info, funcname, varname, value)
- SpecTools.checkResultType(as, info, funcname, varname, value)
- SpecTools.genHMAC(as, info, ftnreq)
- const: SpecTools.standard_errors
##new SpecTools()
SpecTools
##SpecTools.loadIface(as, info, specdirs)
Load FutoIn iface definition.
NOTE: Browser uses XHR to load specs, Node.js searches in local fs.
Params
- as
AsyncSteps
- info
Object
- destination object with "iface" and "version" fields already set - specdirs
Array
- each element - search path/url (string) or raw iface (object)
##SpecTools.parseIface(as, info, specdirs, raw_spec)
Parse raw futoin spec (preloaded)
Params
- as
AsyncSteps
- info
Object
- destination object with "iface" and "version" fields already set - specdirs
Array
- each element - search path/url (string) or raw iface (object) - raw_spec
Object
- iface definition object
##SpecTools.checkConsistency(as, info)
Deeply check consistency of loaded interface.
NOTE: not yet implemented
Params
- as
AsyncSteps
- info
Object
- previously loaded iface
##SpecTools.checkType(info, type, val)
Check if value matches required type
Params
- info
Object
- previously loaded iface - type
string
- standard or custom iface type - val
*
- value to check
Returns: Boolean
##SpecTools.checkParameterType(info, funcname, varname, value)
Check if parameter value matches required type
Params
- info
Object
- previously loaded iface - funcname
string
- function name - varname
string
- parameter name - value
*
- value to check
##SpecTools.checkResultType(as, info, funcname, varname, value)
Check if result value matches required type
Params
- as
AsyncSteps
- info
Object
- previously loaded iface - funcname
string
- function name - varname
string
- result variable name - value
*
- value to check
##SpecTools.genHMAC(as, info, ftnreq)
Generate HMAC
NOTE: for simplicity, 'sec' field must not be present
Params
- as
AsyncSteps
- info
object
- Interface raw info object - ftnreq
object
- Request Object
Returns: Buffer
- Binary HMAC signature
##const: SpecTools.standard_errors
Enumeration of standard errors
#SimpleCCM
window.SimpleCCM - Browser-only reference to futoin-asyncsteps.SimpleCCM
#AdvancedCCM
window.AdvancedCCM - Browser-only reference to futoin-asyncsteps.AdvancedCCM
#Invoker
futoin.Invoker - Browser-only reference to futoin-invoker module
#FutoInInvoker
window.FutoInInvoker - Browser-only reference to futoin-invoker module
documented by jsdoc-to-markdown.