copious-transitions
Version:
Framework for working with frameworks
286 lines (252 loc) • 20.2 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: contractual/transition_processing.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: contractual/transition_processing.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>
const LocalTObjectCache = require('../custom_storage/local_object_cache')
/**
* Transition handling is a collection of POST method responses designed to provide executive action.
* There are just a few methods that guide the process by puting the request through tests supplied by the
* session manager, a validator, and a transition processor until a transition finalization method can be called.
*
* A transition may operate in response to a single request, or it might cache salietn data and utimately achieve finalization
* after negotiating a second request with the requesting client.
*
* The basic method that runs a transition is `transition_handler`. And, if a secondary action is required for a transition,
* the `secondary_transition_handler` method will be invoked in response to the appropriate request from the requesting client.
*
* Two other methods are provided by this class, `ws_transition` and `endpoint_transition`. These methods work in response to
* messages from communication paths other than HTTP communication paths. While the `CopiousTransitions` sets up an HTTP(s) web
* server and handles requests coming to certain types of API paths, the other methods use WebSockets in one case and TCP(tls)
* communication in the second case. These methods call upon `transition_handler` and `secondary_transition_handler` to do their work.
* They will then shape their responses to WS clients or relay clients.
*
* Note that one can imagine a transtion machine implemented explicitly in the application and that a single transition machine instance can
* belong to a session. Some applications may implement the actual transition machine. Often, though, the transition machine
* is a set of calls out to the DB interface or to the transition engine, which might send data somewhere or publish a message.
* The point of these methods is to create a skeleton for the flow of transition processing.
*
* @memberof Contractual
* @extends LocalTObjectCache
*/
class TransitionHandling extends LocalTObjectCache {
//
//
constructor(sess_manager,validator,dynamics,cache_time) {
//
super(cache_time)
this.going_ws_session = {}
//
this.session_manager = sess_manager
this.validator = validator
this.dynamics = dynamics
}
/**
* The transition hanlder is the CopiousTransitions entry point into an application's state transition
* implementation. This method supplies the basic framework for stepping the transition request through permission,
* acceptance, processing setup, until the state transition can be finalized either in response to the first request or
* in response to a secondary request (`secondary_action`).
*
* The transition handler first calls the session manager's guard. The guard can provide a certain amount of access control
* and may also know about the state of the server and the permissibility of certain types of transactions. A failure
* to pass the guard yields a reson of unavailability to the requester.
*
* If the guard is passed, the validator checks the trasition body for addmissable data types, etc. In many use case,
* the call to the validator is moot. Yet, in some operations the application will prvodide checking methods that the
* validator framework can use.
*
* After validation, the transition is examined for feasibility. By feasibility is meant that the state of the server relative to the session
* can allow for the transition to a desired state and that the resources required for the transition are available. The check must be
* determined by the application. The check can be any degree of complexity from something simple such as accepting the name of
* the transition to something quite complicated such as checking that certain machines are attached to the server and that certain
* measurement are with desired ranges. What is provided here, is that the transition server will call on the feasibility test provided
* by the application after validation and before transition processing and, furthermore, the transition handler will wait (await)
* the completion of the feasibility testing.
*
* Requests remaining after they are deemed feasible, can be processed using the session manager's `process_transition`,
* which sets up the data needed for finalization and determines if the transaction will happen in one step or
* require a secondary action.
*
* Those transitions that can be done in one step proceed immediately to finalization. The finalization method, provided
* by the application, should set the state transition for the session. The method should result in a the transition machine
* owned by the session being in an identifiable state. When the session is queried for the state of the machine, the state
* of the last finalization should be reported. A query of the state should remain the same with respect to the session
* until another state transition is requested.
*
* Those transitions requiring a secondary action before finalization will cache data in preparation for the second action to be done
* in response to an ensuing request. The transition handler calls out to the dynamic data producer to produce the data to be cached.
* The transition handler will cache the data using the methods provided by LocalTObjectCache; the data is cached
* into a map structure with the transition's token as the key. Once the data is cached,
* the partial transition object containing data for the client will be sent to the requester along with the parts of the generated data chosen to be sent. Data is sent
* in preparation for the secondary action according to a contract of design established for the synchronization of client and server
* operations and negotiations.
*
* Given the client comes back with the request for the seconary action, the next handler `secondary_transition_handler` will
* continue the process of progression the transtion to finalization.
*
* @param {string} transition - the type of transition the client is requesting. See documentation about tagged transisions.
* @param {object} body
* @param {object} transmision_headers
* @returns {Array} - a tupple really, that has: 1) the status code, 2) the JSON response, 3) possibly data or boolean (false for not in use)
*/
async transition_handler(transition,body,transmision_headers) {
let proceed = await this.session_manager.guard(transition,body,transmision_headers)
if ( !proceed ) { // asset exits, permission granted, etc. (check fail)
return [200,{ 'type' : 'transition', 'OK' : 'false', 'reason' : 'unavailable' },false ]
}
//
if ( this.validator.valid(body,this.validator.field_set[transition]) ) { // A field set may be in the configuration for named transitions - true by default
let is_feasible = await this.session_manager.feasible(transition,body,transmision_headers)
// can this session actually make the transition?
if ( is_feasible ) {
//
let transitionObj = await this.session_manager.process_transition(transition,body,transmision_headers) // either fetch or produced transition data
if ( transitionObj ) {
//
// Require a seconday action as part of the transition for finalization
if ( transitionObj.secondary_action ) {
// elements is purposely vague and may be application sepecific
try {
let [send_elements, store_elements] = await this.dynamics.fetch_elements(transition,transitionObj);
//
transition = ((transitionObj.transition !== undefined) ? transitionObj.transition : transition)
//
let tObjCached = { 'tobj' : transitionObj, 'elements' : store_elements, 'transition' : transition }
this.add_local_cache_transition(transitionObj.token,tObjCached)
//
let t_state = { 'type' : 'transition', 'OK' : 'true', 'transition' : transitionObj, 'elements' : send_elements }
return [200,t_state]
} catch(e) {
console.log(e)
// nothing really... just report that you can't
}
} else {
// Send back a finalization of transition right away.
body.token = transitionObj.token
// FINALIZE (not a final state) -- means that the state finally makes the transition
let finalization_state = await this.session_manager.finalize_transition(transition,body,{},transmision_headers)
if ( finalization_state ) { // relay the finalized transition and go on with business.
let state = finalization_state.state
let OK = finalization_state.OK
let t_state = { 'type' : 'finalize', 'OK' : OK, 'state' : state, 'reason' : 'matched' }
return [200,t_state]
}
}
//
}
//
}
}
return [200,{ 'type' : 'transition', 'OK' : 'false', 'reason' : 'unavailable' }]
}
/**
* This method progresses a transtion request towards finalization provided that the transition can be identified by its token.
* The previously generated data that was not sent to the client will be extracted from the transition object keyed by the token.
*
* Just one check, a match between the object sent in the request from the client and the cached transition object needs to pass.
* The match test might be one of a number of possible checks, ranging in in complexity from the check to see is a field is present, to
* checking if same name fields of the two objects are equal, to signature verification using elliptic key crypotgraphy, or perhaps more.
* The match implementation is part of the application.
*
* Once the match is passed, the secondary transition handler calls up the transition finalization method for the transition machine
* operating with respect to the current session.
*
*
* @param {object} body
* @param {object} transmision_headers
* @returns {Array} - a tupple really, that has: 1) the status code, 2) the JSON response, 3) possibly data or boolean (false for not in use)
*/
async secondary_transition_handler(body,transmision_headers) {
if ( body.token !== undefined ) {
let cached_transition = this.fetch_local_cache_transition(body.token,body.next)
if ( cached_transition !== undefined ) {
if ( this.session_manager.match(body,cached_transition) ) { // check on matching tokens and possibly other things
// some kind of transition takes place and becomes the state of the session. It may not be the same as the one
// specified in the cached transition, but may be similar depending on how types (categories) are regulated
let elements = cached_transition.elements
let finalization_state = await this.session_manager.finalize_transition(cached_transition.transition,body,elements,transmision_headers) // FINALIZE (not a final state)
if ( finalization_state ) { // relay the finalized transition and go on with business.
let state = finalization_state.state
let OK = finalization_state.OK // as a string
let t_state = { 'type' : 'finalize', 'OK' : OK, 'state' : state, 'reason' : 'matched' }
return [200,t_state]
} // else nothing worked
}
}
}
return [200,{ 'type' : 'transition', 'OK' : 'false', 'reason' : 'unavailable' } ]
}
/**
* This method does a very short one step version of transtion processing in response to websocket
* messages inbound from the client. This method only check on the feasiblily of the transition and
* if it finds it feasible, the transition will be move on to finalization.
*
* @param {string} transition
* @param {object} body
* @returns {Array} - a tupple really, that has: 1) the status code, 2) the JSON response, 3) possibly data or boolean (false for not in use)
*/
async ws_transition(transition,body) {
let is_feasible = await this.session_manager.feasible(transition,body,null)
if ( is_feasible ) {
let finalization_state = await this.session_manager.finalize_transition(transition,body,{},null) // FINALIZE (not a final state)
if ( finalization_state ) {
return finalization_state
}
}
return false
}
/**
* This method is named `endpoint_transition` due to its servicing the operations of an endpoint server (as defined in the package
* message-relay-server). This method looks for a token on the message (body). If the token is not there, it assumes the
* message arriving at the endpoint is in the first phase of transition processing and sends the data on to the transition handler.
*
* If the token is present, the method assumes that the message is targeted to the secondary action.
*
* The branches return the result of the methods they call, and the UserMessageEndpoint instance is written to
* send the response back to the relay client (message-relay-server) in an appropriate form using the transtion hanlder results.
*
* @param {string} transition
* @param {object} body
* @returns {Array} - a tupple really, that has: 1) the status code, 2) the JSON response, 3) possibly data or boolean (false for not in use)
*/
async endpoint_transition(transition,body) {
try {
if ( !(body.token) ) { // no transition token ... so treat this as primary
return await this.transition_handler(transition,body,{})
} else {
return await this.secondary_transition_handler(body,{})
}
} catch (e) {
return [200,{ 'type' : 'transition', 'OK' : 'false', 'reason' : 'unavailable' } ]
}
}
}
module.exports = TransitionHandling</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Namespaces</h3><ul><li><a href="Contractual.html">Contractual</a></li><li><a href="CopiousTransitions.html">CopiousTransitions</a></li><li><a href="DefaultDB.html">DefaultDB</a></li><li><a href="base.html">base</a></li><li><a href="field_validators.html">field_validators</a></li></ul><h3>Classes</h3><ul><li><a href="Contractual.LocalTObjectCache.html">LocalTObjectCache</a></li><li><a href="Contractual.MimeHandling.html">MimeHandling</a></li><li><a href="Contractual.TransitionHandling.html">TransitionHandling</a></li><li><a href="Contractual.UserHandling.html">UserHandling</a></li><li><a href="CopiousTransitions.CopiousTransitions.html">CopiousTransitions</a></li><li><a href="DefaultDB.CustomizationMethodsByApplication.html">CustomizationMethodsByApplication</a></li><li><a href="DefaultDB.FauxInMemStore.html">FauxInMemStore</a></li><li><a href="DefaultDB.FileMapper.html">FileMapper</a></li><li><a href="DefaultDB.FilesAndRelays.html">FilesAndRelays</a></li><li><a href="DefaultDB.FilesAndRelays_base.html">FilesAndRelays_base</a></li><li><a href="DefaultDB.LocalStaticDB.html">LocalStaticDB</a></li><li><a href="DefaultDB.LocalStorageLifeCycle.html">LocalStorageLifeCycle</a></li><li><a href="DefaultDB.LocalStorageSerialization.html">LocalStorageSerialization</a></li><li><a href="DefaultDB.PageableMemStoreElement.html">PageableMemStoreElement</a></li><li><a href="DefaultDB.PersistenceContracts.html">PersistenceContracts</a></li><li><a href="DefaultDB.RemoteMessaging.html">RemoteMessaging</a></li><li><a href="DefaultDB.StaticDBDefault.html">StaticDBDefault</a></li><li><a href="GeneralUserDBWrapperImpl.html">GeneralUserDBWrapperImpl</a></li><li><a href="SessionTokenManager.html">SessionTokenManager</a></li><li><a href="base.DBClass.html">DBClass</a></li><li><a href="base.EndpointManager.html">EndpointManager</a></li><li><a href="base.GeneralAppLifeCycle.html">GeneralAppLifeCycle</a></li><li><a href="base.GeneralAuth.html">GeneralAuth</a></li><li><a href="base.GeneralBusiness.html">GeneralBusiness</a></li><li><a href="base.GeneralDynamic.html">GeneralDynamic</a></li><li><a href="base.GeneralMiddleWare.html">GeneralMiddleWare</a></li><li><a href="base.GeneralStatic.html">GeneralStatic</a></li><li><a href="base.GeneralTransitionEngImpl.html">GeneralTransitionEngImpl</a></li><li><a href="base.SessionManager.html">SessionManager</a></li><li><a href="base.SessionManager_Lite.html">SessionManager_Lite</a></li><li><a href="base.TaggedTransition.html">TaggedTransition</a></li><li><a href="base.TokenTables.html">TokenTables</a></li><li><a href="base.UserMessageEndpoint.html">UserMessageEndpoint</a></li><li><a href="base.WebSocketManager.html">WebSocketManager</a></li><li><a href="field_validators.DataLookupField.html">DataLookupField</a></li><li><a href="field_validators.EmailField.html">EmailField</a></li><li><a href="field_validators.EmailVerifyField.html">EmailVerifyField</a></li><li><a href="field_validators.FieldTest.html">FieldTest</a></li><li><a href="field_validators.FieldValidatorTools.html">FieldValidatorTools</a></li><li><a href="field_validators.ForeignAuth.html">ForeignAuth</a></li><li><a href="field_validators.GeneralValidator.html">GeneralValidator</a></li><li><a href="field_validators.LengthyAlphabetField.html">LengthyAlphabetField</a></li><li><a href="field_validators.LengthyDigitalField.html">LengthyDigitalField</a></li><li><a href="field_validators.LengthyField.html">LengthyField</a></li><li><a href="field_validators.LengthyStringField.html">LengthyStringField</a></li><li><a href="field_validators.PasswordField.html">PasswordField</a></li><li><a href="field_validators.PasswordVerifyField.html">PasswordVerifyField</a></li><li><a href="field_validators.TypeCheckField.html">TypeCheckField</a></li></ul><h3>Global</h3><ul><li><a href="global.html#generate_password_block">generate_password_block</a></li><li><a href="global.html#load_configuration">load_configuration</a></li><li><a href="global.html#load_parameters">load_parameters</a></li><li><a href="global.html#module_top">module_top</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> on Tue Oct 31 2023 17:32:59 GMT-0700 (Pacific Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>