Browse Source

chore: add optional priority to local state set actions

Fela Maslen 4 năm trước cách đây
mục cha
commit
211a09369b

+ 15 - 10
gmus-web/src/actions/actions.ts

@@ -1,8 +1,15 @@
-import { SetStateAction } from 'react';
-import { Song } from '../types';
-import { Member, MusicPlayer } from '../types/state';
-import { ActionErrorOccurred } from './error';
-import { ActionLocal, ActionRemote, ActionTypeLocal, ActionTypeRemote } from './types';
+import type { SetStateAction } from 'react';
+
+import type { Song } from '../types';
+import type { Member, MusicPlayer } from '../types/state';
+import type { ActionErrorOccurred } from './error';
+import {
+  ActionLocal,
+  ActionRemote,
+  ActionTypeLocal,
+  ActionTypeRemote,
+  LocalStateSetPayload,
+} from './types';
 
 export * from './types';
 
@@ -22,16 +29,14 @@ export const nameSet = (name: string): ActionNameSet => ({
   payload: name,
 });
 
-export type ActionStateSetLocal = ActionLocal<
-  ActionTypeLocal.StateSet,
-  SetStateAction<Omit<Partial<MusicPlayer>, 'seekTime'>>
->;
+export type ActionStateSetLocal = ActionLocal<ActionTypeLocal.StateSet, LocalStateSetPayload>;
 
 export const stateSet = (
   payload: SetStateAction<Partial<MusicPlayer>> = {},
+  priority = 0,
 ): ActionStateSetLocal => ({
   type: ActionTypeLocal.StateSet,
-  payload,
+  payload: { payload, priority },
 });
 
 export type ActionSeeked = ActionLocal<ActionTypeLocal.Seeked, number>;

+ 9 - 0
gmus-web/src/actions/types.ts

@@ -1,3 +1,7 @@
+import type { SetStateAction } from 'react';
+
+import type { MusicPlayer } from '../types';
+
 // Remote actions - these only come FROM the socket
 export enum ActionTypeRemote {
   StateSet = 'STATE_SET',
@@ -32,3 +36,8 @@ export type ActionRemote<T extends ActionTypeRemote = ActionTypeRemote, P = unkn
 > & { priority: number; fromClient?: string | null };
 
 export type ActionLocal<T extends ActionTypeLocal = ActionTypeLocal, P = unknown> = Action<T, P>;
+
+export type LocalStateSetPayload = {
+  payload: SetStateAction<Partial<MusicPlayer>>;
+  priority?: number;
+};

+ 2 - 2
gmus-web/src/effects/effects.spec.ts

@@ -38,13 +38,13 @@ describe(globalEffects.name, () => {
         shuffleMode: false,
       };
 
-      const action = stateSet(localPlayer);
+      const action = stateSet(localPlayer, 3);
 
       const result = globalEffects(state, action);
 
       expect(result).toStrictEqual<ActionStateSetRemote>({
         type: ActionTypeRemote.StateSet,
-        priority: 0,
+        priority: 3,
         payload: { ...state.player, ...localPlayer },
       });
     });

+ 1 - 1
gmus-web/src/effects/effects.ts

@@ -51,7 +51,7 @@ function sendStateUpdateToServer(
   }
   return {
     type: ActionTypeRemote.StateSet,
-    priority: 0,
+    priority: action.payload.priority ?? 0,
     payload: nextPlayer,
   };
 }

+ 13 - 4
gmus-web/src/selectors.ts

@@ -4,11 +4,12 @@ import { MusicPlayer } from './types';
 
 export function getNextPlayerStateFromAction(
   player: MusicPlayer | undefined,
-  payload: ActionStateSetLocal['payload'] | null,
+  action: ActionStateSetLocal['payload'] | ActionStateSetRemote | null,
 ): MusicPlayer | null {
-  if (!(payload && player)) {
+  if (!(action && player)) {
     return null;
   }
+  const { payload } = action;
   if (typeof payload === 'function') {
     return { ...player, ...payload(player) };
   }
@@ -26,15 +27,23 @@ export const isFromOurselves = (
   action: ActionRemote,
 ): boolean => state.myClientName === action.fromClient;
 
+const isLocalStateSet = (
+  action: ActionStateSetLocal | ActionStateSetRemote,
+): action is ActionStateSetLocal => Reflect.has(action.payload ?? {}, 'priority');
+
 export const willBeMaster = (
   state: Partial<GlobalState> & Pick<GlobalState, 'myClientName'>,
-  action: ActionStateSetLocal | ActionStateSetRemote,
+  fullAction: ActionStateSetLocal | ActionStateSetRemote,
 ): boolean => {
+  const action: ActionStateSetLocal['payload'] | ActionStateSetRemote = isLocalStateSet(fullAction)
+    ? fullAction.payload
+    : fullAction;
+
   const actionHasMaster =
     typeof action.payload === 'function' ? !!action.payload({}).master : !!action.payload?.master;
   return (
     actionHasMaster &&
-    state.myClientName === getNextPlayerStateFromAction(state.player, action.payload)?.master
+    state.myClientName === getNextPlayerStateFromAction(state.player, action)?.master
   );
 };