UNPKG

copious-transitions

Version:
286 lines (252 loc) 20.2 kB
<!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>