Skip to content

Commit

Permalink
feat(plugins): Consolidate flush and validate plugins (#970)
Browse files Browse the repository at this point in the history
  • Loading branch information
delucis authored Aug 1, 2021
1 parent d559866 commit 1e435c2
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 12 deletions.
5 changes: 2 additions & 3 deletions src/core/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
*/

import { ProcessGameConfig } from './game';
import type { Game } from '../types';
import * as plugins from '../plugins/main';
import type { PartialGameState, State, Ctx } from '../types';
import type { Ctx, Game, PartialGameState, State } from '../types';

/**
* Creates the initial game state.
Expand Down Expand Up @@ -61,7 +60,7 @@ export function InitializeGame({
};

initial = game.flow.init(initial);
initial = plugins.Flush(initial, { game });
[initial] = plugins.FlushAndValidate(initial, { game });

// Initialize undo stack.
if (!game.disableUndo) {
Expand Down
11 changes: 4 additions & 7 deletions src/core/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,22 +130,19 @@ function initializeDeltalog(

/**
* Update plugin state after move/event & check if plugins consider the action to be valid.
* @param newState Latest version of state in the reducer.
* @param oldState Initial value of state when reducer started its work.
* @param state Current version of state in the reducer.
* @param oldState State to revert to in case of error.
* @param pluginOpts Plugin configuration options.
* @returns Tuple of the new state updated after flushing plugins and the old
* state augmented with an error if a plugin declared the action invalid.
*/
function flushAndValidatePlugins(
newState: State,
state: State,
oldState: State,
pluginOpts: { game: Game; isClient?: boolean }
): [State, TransientState?] {
newState = plugins.Flush(newState, pluginOpts);
const isInvalid = plugins.IsInvalid(newState, pluginOpts);
const [newState, isInvalid] = plugins.FlushAndValidate(state, pluginOpts);
if (!isInvalid) return [newState];
const { plugin, message } = isInvalid;
error(`plugin declared action invalid: ${plugin} - ${message}`);
return [
newState,
WithError(oldState, ActionErrorType.PluginActionInvalid, isInvalid),
Expand Down
18 changes: 16 additions & 2 deletions src/plugins/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
ActionShape,
PlayerID,
} from '../types';
import { error } from '../core/logger';

interface PluginOpts {
game: Game;
Expand Down Expand Up @@ -166,7 +167,7 @@ export const Enhance = (
/**
* Allows plugins to update their state after a move / event.
*/
export const Flush = (state: State, opts: PluginOpts): State => {
const Flush = (state: State, opts: PluginOpts): State => {
// We flush the events plugin first, then custom plugins and the core plugins.
// This means custom plugins cannot use the events API but will be available in event hooks.
// Note that plugins are flushed in reverse, to allow custom plugins calling each other.
Expand Down Expand Up @@ -246,7 +247,7 @@ export const NoClient = (state: State, opts: PluginOpts): boolean => {
* Allows plugins to indicate if the entire action should be thrown out
* as invalid. This will cancel the entire state update.
*/
export const IsInvalid = (
const IsInvalid = (
state: State,
opts: PluginOpts
): false | { plugin: string; message: string } => {
Expand All @@ -270,6 +271,19 @@ export const IsInvalid = (
return firstInvalidReturn || false;
};

/**
* Update plugin state after move/event & check if plugins consider the update to be valid.
* @returns Tuple of `[updatedState]` or `[originalState, invalidError]`.
*/
export const FlushAndValidate = (state: State, opts: PluginOpts) => {
const updatedState = Flush(state, opts);
const isInvalid = IsInvalid(updatedState, opts);
if (!isInvalid) return [updatedState] as const;
const { plugin, message } = isInvalid;
error(`${plugin} plugin declared action invalid:\n${message}`);
return [state, isInvalid] as const;
};

/**
* Allows plugins to customize their data for specific players.
* For example, a plugin may want to share no data with the client, or
Expand Down

0 comments on commit 1e435c2

Please sign in to comment.