From f6d1102fd62f587bf2036e8195c6eb305feafbce Mon Sep 17 00:00:00 2001 From: REllEK-IO Date: Fri, 17 May 2024 10:44:08 -0700 Subject: [PATCH] True Consistency Update v0.1.72 --- Axium.md | 41 ++++++----- README.md | 5 +- package.json | 2 +- src/concepts/axium/axium.concept.ts | 6 +- .../qualities/registerTimeOut.quality.ts | 40 ++++++++++ src/index.ts | 17 ++++- src/model/time.ts | 39 ++++++---- .../axiumRegisterTimeOut.test.ts | 73 +++++++++++++++++++ 8 files changed, 181 insertions(+), 42 deletions(-) create mode 100644 src/concepts/axium/qualities/registerTimeOut.quality.ts create mode 100644 src/test/axiumRegisterTimeOut/axiumRegisterTimeOut.test.ts diff --git a/Axium.md b/Axium.md index 2760ed9..1858dad 100644 --- a/Axium.md +++ b/Axium.md @@ -112,31 +112,32 @@ export type AxiumState = { ## Axium Qualities for Internal Use Please avoid using these qualities, but are providing explanations to understand the inner workings of the axium. -* addConceptsFromQue - This will be ran from the internal axium principle and take all concepts added to said que to include within the axium and increment the current generation. -* appendActionListToDialog - Takes the final output of a strategy and appends such into a Stratimux dialog if storeDialog is set to True. -* badAction - If logging is set to true, this will log any BadAction via its payload of the invalidated action that is created from the primeAction() helper function. -* conclude - This is a pure action that has no reducer or method. And will only be issued upon the conclusion of an ActionStrategy. If ownership is part of the concept load. This allows for the conclude to clear the final action's locks via its OwnershipLedger Entries. -* initializePrinciples - Is a delayed action to allow for the internal set up of the axium at run time. -* open - Similar to conclude, notifies principles when the axium is open to their emissions. Part of the initialization, addConcept, and removeConcept strategies. -* close - This will will cancel all internal subscriptions that the axium has access to. As well as all Steams will be completed. The external close() function that the createAxium supplies, dispatches this action. Or can be ran specially via an internal principle towards its governing axium or that of another axium that it is subscribed to. -* removeConceptsViaQue - This will run via the internal axium principle. Whenever there is an addition to this remove que. +* axiumAddConceptsFromQue - This will be ran from the internal axium principle and take all concepts added to said que to include within the axium and increment the current generation. +* axiumAppendActionListToDialog - Takes the final output of a strategy and appends such into a Stratimux dialog if storeDialog is set to True. +* axiumBadAction - If logging is set to true, this will log any BadAction via its payload of the invalidated action that is created from the primeAction() helper function. +* axiumConclude - This is a pure action that has no reducer or method. And will only be issued upon the conclusion of an ActionStrategy. If ownership is part of the concept load. This allows for the conclude to clear the final action's locks via its OwnershipLedger Entries. +* axiumInitializePrinciples - Is a delayed action to allow for the internal set up of the axium at run time. +* axiumOpen - Similar to conclude, notifies principles when the axium is open to their emissions. Part of the initialization, addConcept, and removeConcept strategies. +* axiumClose - This will will cancel all internal subscriptions that the axium has access to. As well as all Steams will be completed. The external close() function that the createAxium supplies, dispatches this action. Or can be ran specially via an internal principle towards its governing axium or that of another axium that it is subscribed to. +* axiumRemoveConceptsViaQue - This will run via the internal axium principle. Whenever there is an addition to this remove que. ## Use With Care *These are part of the add and remove concept strategies. And while internal could be used if required.* -* setBlockingMode - Sets the mode to blocking and open to False. This would notify any principles to cease detecting for changes. This is part of the add and remove concept strategies. And while internal could be used if required. -* setDefaultMode - Sets the modeIndex to the defaultModeIndex and open to True. This informs principles that it is clear to detect changes. +* axiumSetBlockingMode - Sets the mode to blocking and open to False. This would notify any principles to cease detecting for changes. This is part of the add and remove concept strategies. And while internal could be used if required. +* axiumSetDefaultMode - Sets the modeIndex to the defaultModeIndex and open to True. This informs principles that it is clear to detect changes. ## Useful Axium Qualities -* open - Sets axium open property by default to True if no payload is supplied. Must be used after setBlockingMode in a strategy to reenable functionality of principles and external subscribers. -* log - Merely Logs the action, is useful for debugging ActionStrategies as it logs attached Strategy, its current ActionList, and any addition action qualities. -* preClose - Will prompt the axium to close and disengage all active subscriptions, while notifying subscribers that their concept has been removed. -* setMode - If your concept requires a specific modification to the functionality of the stream. This will set the mode index to that stream. Specifically this shouldn't have to be used. But is left to the developer if they run into such a case. -* setDefaultModeIndex - Should be used if your mode is to be considered the default mode of your application. For utilization within a strategy after setMode. Be sure to a run time search for your concept name and mode, after your concept is added via the addConcept strategy found below. Be mindful that modeName is just your Concept Name and the creation of new Modes should be the last go To for your applications functionality. -* clearDialog - Clears the currently stored Stratimux dialog, may be used within a strategy. -* clearBadActionTypeFromBadActionList - This is to allow for plans to take into account for expired actions and clear such. -* clearBadStrategyTopicFromBadActionList - Allows plans to accounts for specific ActionStrategy topics that might find themselves in badActions and clear such. -* clearBadPlanFromBadPlanList - This additionally allows for concepts to take into account potentially failed plans that are set by axium.plan(). Via their topic as payload and clears such. -* kick - This is a pure action that will just trigger the next function via the UnifiedSubject to prime subscribers or stages. Noting that the downside of Stratimux's halting quality, is you have to kick it into gear if it hasn't received an action recently for your staged Plans to operate as intended. +* axiumOpen - Sets axium open property by default to True if no payload is supplied. Must be used after setBlockingMode in a strategy to reenable functionality of principles and external subscribers. +* axiumLog - Merely Logs the action, is useful for debugging ActionStrategies as it logs attached Strategy, its current ActionList, and any addition action qualities. +* axiumPreClose - Will prompt the axium to close and disengage all active subscriptions, while notifying subscribers that their concept has been removed. +* axiumSetMode - If your concept requires a specific modification to the functionality of the stream. This will set the mode index to that stream. Specifically this shouldn't have to be used. But is left to the developer if they run into such a case. +* axiumSetDefaultModeIndex - Should be used if your mode is to be considered the default mode of your application. For utilization within a strategy after setMode. Be sure to a run time search for your concept name and mode, after your concept is added via the addConcept strategy found below. Be mindful that modeName is just your Concept Name and the creation of new Modes should be the last go To for your applications functionality. +* axiumClearDialog - Clears the currently stored Stratimux dialog, may be used within a strategy. +* axiumClearBadActionTypeFromBadActionList - This is to allow for plans to take into account for expired actions and clear such. +* axiumClearBadStrategyTopicFromBadActionList - Allows plans to accounts for specific ActionStrategy topics that might find themselves in badActions and clear such. +* axiumClearBadPlanFromBadPlanList - This additionally allows for concepts to take into account potentially failed plans that are set by axium.plan(). Via their topic as payload and clears such. +* axiumKick - This is a pure action that will just trigger the next function via the UnifiedSubject to prime subscribers or stages. Noting that the downside of Stratimux's halting quality, is you have to kick it into gear if it hasn't received an action recently for your staged Plans to operate as intended. +* axiumRegisterTimeOut - This will call the axiumTimeOut function on the incoming payload's act and timeOut properties. Then will succeed a strategy if present. ## Axium Strategies Concept Set Transformation ```typescript diff --git a/README.md b/README.md index 7e48598..73e0ec9 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,10 @@ When in doubt simplify. * [Unified Turing Machine](https://github.com/Phuire-Research/Stratimux/blob/main/The-Unified-Turing-Machine.md) - The governing concept for this entire framework. ## Change Log ![Tests](https://github.com/Phuire-Research/Stratimux/actions/workflows/node.js.yml/badge.svg) -### Consistency Update v0.1.71 5/16/2024 +### *Consistency Update* v0.1.72 +* Added a new Axium Quality: **axiumRegisterTimeOut**, that accepts an action and specified timeout that will run the axiumTimeOut function then succeed an incoming strategy if present. + * This likewise fulfills the original purpose of buffer, even in a complex scenario. +### v0.1.71 5/16/2024 * Finally removed the need to add "as Subject | UnifiedSubject" when creating methods that access state or concepts. * Added then **removed** a new Buffer Method Creator Series. See branch Stash-Buffer for details. ### v0.1.69 5/15/2024 diff --git a/package.json b/package.json index 7ab36a8..7518180 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "stratimux", "license": "GPL-3.0", - "version": "0.1.71", + "version": "0.1.72", "description": "Unified Turing Machine", "main": "dist/index.js", "module": "dist/index.mjs", diff --git a/src/concepts/axium/axium.concept.ts b/src/concepts/axium/axium.concept.ts index 0364c9a..a3d556a 100644 --- a/src/concepts/axium/axium.concept.ts +++ b/src/concepts/axium/axium.concept.ts @@ -36,6 +36,7 @@ import { axiumRegisterStagePlannerQuality } from './qualities/registerStagePlann import { axiumKickQuality } from './qualities/kick.quality'; import { axiumPreCloseQuality } from './qualities/preClose.quality'; import { axiumStitchQuality } from './qualities/stitch.quality'; +import { axiumRegisterTimeOutQuality } from './qualities/registerTimeOut.quality'; export type NamedSubscription = { name: string; @@ -73,7 +74,7 @@ export type AxiumState = { badPlans: Plan[]; badActions: Action[]; timer: NodeJS.Timeout[]; - timerLedger: Map Action)[], number]> + timerLedger: Map Action)[]> head: Action[]; body: Action[]; tail: Action[]; @@ -148,7 +149,8 @@ export const createAxiumConcept = (name: string, storeDialog?: boolean, logging? axiumClearBadActionTypeFromBadActionListQuality, axiumClearBadStrategyTopicFromBadActionListQuality, axiumClearBadPlanFromBadPlanListQuality, - axiumStitchQuality + axiumStitchQuality, + axiumRegisterTimeOutQuality ], [axiumPrinciple, axiumClosePrinciple], [blockingMode, permissiveMode] diff --git a/src/concepts/axium/qualities/registerTimeOut.quality.ts b/src/concepts/axium/qualities/registerTimeOut.quality.ts new file mode 100644 index 0000000..d542e00 --- /dev/null +++ b/src/concepts/axium/qualities/registerTimeOut.quality.ts @@ -0,0 +1,40 @@ +/*<$ +For the asynchronous graph programming framework Stratimux and Axium Concept, +generate a quality that will register a subscription to the concepts$ stream. +This allows for the clean closure of concepts that are removed or when the axium itself exits. +$>*/ +/*<#*/ +import { defaultReducer, nullReducer } from '../../../model/concept'; +import { selectPayload } from '../../../model/selector'; +import { createQualitySetWithPayload } from '../../../model/quality'; +import { createMethodWithConcepts } from '../../../model/method'; +import { axiumTimeOut } from '../../../model/time'; +import { Action } from '../../../model/action'; +import { strategySuccess } from '../../../model/actionStrategy'; + +export type AxiumRegisterTimeOutPayload = { + act: Action; + timeOut: number +} + +export const [ + axiumRegisterTimeOut, + axiumRegisterTimeOutType, + axiumRegisterTimeOutQuality +] = createQualitySetWithPayload({ + type: 'register an Action to Axium\'s timerLedger', + reducer: defaultReducer, + methodCreator: (concepts$, semaphore) => createMethodWithConcepts((action, concepts) => { + const { + act, + timeOut + } = selectPayload(action); + axiumTimeOut(concepts, () => act, timeOut); + if (action.strategy) { + return strategySuccess(action.strategy); + } else { + return action; + } + }, concepts$, semaphore) +}); +/*#>*/ \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index e9d56db..fdb8399 100644 --- a/src/index.ts +++ b/src/index.ts @@ -171,15 +171,25 @@ export { AxiumRegisterStagePlannerPayload, axiumRegisterStagePlannerType } from './concepts/axium/qualities/registerStagePlanner.quality'; -export { axiumClearDialog, axiumClearDialogType } from './concepts/axium/qualities/clearDialog.quality'; -export { axiumSetDefaultMode, +export { + axiumClearDialog, + axiumClearDialogType +} from './concepts/axium/qualities/clearDialog.quality'; +export { + axiumSetDefaultMode, axiumSetDefaultModeType, AxiumSetDefaultModePayload } from './concepts/axium/qualities/setDefaultMode.quality'; -export { axiumSetBlockingMode, +export { + axiumSetBlockingMode, axiumSetBlockingModeType, AxiumSetBlockingModePayload } from './concepts/axium/qualities/setBlockingMode.quality'; +export { + axiumRegisterTimeOut, + AxiumRegisterTimeOutPayload, + axiumRegisterTimeOutType +} from './concepts/axium/qualities/registerTimeOut.quality'; // Strategies export { addConceptsToAddQueThenBlockStrategy, @@ -189,7 +199,6 @@ export { addConceptsToRemovalQueThenBlockStrategy, addConceptsToRemovalQueThenBlockTopic } from './concepts/axium/strategies/removeConcept.strategy'; - // Counter export { CounterState, counterName, createCounterConcept } from './concepts/counter/counter.concept'; export { counterSelectCount } from './concepts/counter/counter.selector'; diff --git a/src/model/time.ts b/src/model/time.ts index 3fc3479..0fa1762 100644 --- a/src/model/time.ts +++ b/src/model/time.ts @@ -23,13 +23,16 @@ const handleTimedRun = (axiumState: AxiumState, func: (() => Action)[], timed: n }); axiumState.timer.shift(); axiumState.timerLedger.delete(timed); - const timerKeys = Object.keys(axiumState.timerLedger); + const timerKeys: number[] = []; + axiumState.timerLedger.forEach((_, key) => { + timerKeys.push(key); + }); if (timerKeys.length > 0) { - const timerList = timerKeys.map(t => Number(t)).sort((a, b) => a - b); + const timerList = timerKeys.sort((a, b) => a - b); const slot = axiumState.timerLedger.get(timerList[0]); if (slot) { - const someTime = slot[1] - Date.now(); - axiumState.timer.push(setTimeout(() => handleTimedRun(axiumState, slot[0], slot[1]), someTime >= 0 ? someTime : 0)); + const someTime = timerList[0] - Date.now(); + axiumState.timer.push(setTimeout(() => handleTimedRun(axiumState, slot, timerList[0]), someTime >= 0 ? someTime : 0)); } } if (axiumState.tailTimer.length === 0) { @@ -48,35 +51,43 @@ export const axiumTimeOut = (concepts: Concepts, func: () => Action, timeOut: nu const timer = axiumState.timer.length > 0 ? axiumState.timer[0] : undefined; if (timer) { // If timer exists, first index of timerList would exist - const timerList = Object.keys(ledger).map(t => Number(t)).sort((a, b) => a - b); + const timerKeys: number[] = []; + axiumState.timerLedger.forEach((_, key) => { + timerKeys.push(key); + }); + const timerList = timerKeys.sort((a, b) => a - b); if (timerList[0] > timed) { clearTimeout(timer); axiumState.timer.shift(); const slot = axiumState.timerLedger.get(timed); if (slot) { - slot[0].push(func); - ledger.set(timed, [slot[0], timed]); + slot.push(func); axiumState.timer.push(setTimeout(() => { - handleTimedRun(axiumState, slot[0], timed); + handleTimedRun(axiumState, slot, timed); }, timeOut)); } else { - ledger.set(timed, [[func], timed]); + ledger.set(timed, [func]); + const slotted = ledger.get(timed) as (() => Action)[]; axiumState.timer.push(setTimeout(() => { - handleTimedRun(axiumState, [func], timed); + handleTimedRun(axiumState, slotted, timed); }, timeOut)); } } else { const slot = axiumState.timerLedger.get(timed); if (slot) { - slot[0].push(func); - ledger.set(timed, [slot[0], timed]); + slot.push(func); + ledger.set(timed, slot); + } else { + ledger.set(timed, [func]); } } } else { - ledger.set(timed, [[func], timed]); + ledger.set(timed, [func]); + const slotted = ledger.get(timed) as (() => Action)[]; axiumState.timer.push(setTimeout(() => { - handleTimedRun(axiumState, [func], timed); + handleTimedRun(axiumState, slotted, timed); }, timeOut)); } }; + /*#>*/ \ No newline at end of file diff --git a/src/test/axiumRegisterTimeOut/axiumRegisterTimeOut.test.ts b/src/test/axiumRegisterTimeOut/axiumRegisterTimeOut.test.ts new file mode 100644 index 0000000..f392634 --- /dev/null +++ b/src/test/axiumRegisterTimeOut/axiumRegisterTimeOut.test.ts @@ -0,0 +1,73 @@ +/*<$ +For the asynchronous graph programming framework Stratimux, generate a tests and demonstrates how register timeout quality functions. +$>*/ +/*<#*/ +import { axiumKick } from '../../concepts/axium/qualities/kick.quality'; +import { axiumRegisterTimeOut } from '../../concepts/axium/qualities/registerTimeOut.quality'; +import { CounterState, counterName, createCounterConcept } from '../../concepts/counter/counter.concept'; +import { counterSelectCount } from '../../concepts/counter/counter.selector'; +import { counterAdd } from '../../concepts/counter/qualities/add.quality'; +import { createAxium } from '../../model/axium'; +import { selectState } from '../../model/selector'; +import { createStage, stageWaitForOpenThenIterate } from '../../model/stagePlanner'; + +test('Axium Register Time Out', (done) => { + const axium = createAxium('timeout defer actions', [createCounterConcept()]); + const plan = axium.plan('timeout add 4 after 10ms', [ + stageWaitForOpenThenIterate(() => axiumKick()), + createStage((_, dispatch) => { + dispatch(axiumRegisterTimeOut({ + act: counterAdd(), + timeOut: 50 + }), { + iterateStage: true, + }); + }), + createStage((concepts, dispatch) => { + const counterState = selectState(concepts, counterName); + expect(counterState?.count).toBe(0); + dispatch(axiumRegisterTimeOut({ + act: counterAdd(), + timeOut: 50 + }), { + iterateStage: true, + }); + }), + createStage((concepts, dispatch) => { + const counterState = selectState(concepts, counterName); + expect(counterState?.count).toBe(0); + dispatch(axiumRegisterTimeOut({ + act: counterAdd(), + timeOut: 50 + }), { + iterateStage: true, + }); + }), + createStage((concepts, dispatch) => { + const counterState = selectState(concepts, counterName); + expect(counterState?.count).toBe(0); + dispatch(axiumRegisterTimeOut({ + act: counterAdd(), + timeOut: 50 + }), { + iterateStage: true, + }); + }), + createStage((concepts, _dispatch, changes) => { + const counterState = selectState(concepts, counterName); + if (changes.length > 0) { + expect(counterState?.count).toBe(4); + setTimeout(() => { + plan.conclude(); + axium.close(); + done(); + }, 10); + } + }, {selectors: [counterSelectCount], beat: 200}), + createStage(() => { + plan.conclude(); + }) + ]); +}); + +/*#>*/ \ No newline at end of file