diff --git a/packages/core/src/services/command/command.service.ts b/packages/core/src/services/command/command.service.ts index 57f70e03ce..839a6dd633 100644 --- a/packages/core/src/services/command/command.service.ts +++ b/packages/core/src/services/command/command.service.ts @@ -131,6 +131,13 @@ export interface IExecutionOptions { export type CommandListener = (commandInfo: Readonly, options?: IExecutionOptions) => void; export interface ICommandService { + /** + * Check if a command is already registered at the current command service. + * + * @param commandId The id of the command. + */ + hasCommand(commandId: string): boolean; + registerCommand(command: ICommand): IDisposable; registerMultipleCommand(command: ICommand): IDisposable; @@ -177,6 +184,10 @@ export class CommandRegistry { }); } + hasCommand(id: string): boolean { + return this._commands.has(id); + } + getCommand(id: string): [ICommand] | null { if (!this._commands.has(id)) { return null; @@ -188,6 +199,12 @@ export class CommandRegistry { interface ICommandExecutionStackItem extends ICommandInfo {} +export const NilCommand: ICommand = { + id: 'nil', + type: CommandType.COMMAND, + handler: () => true, +}; + export class CommandService implements ICommandService { private readonly _commandRegistry: CommandRegistry; @@ -208,6 +225,10 @@ export class CommandService implements ICommandService { this._registerCommand(NilCommand); } + hasCommand(commandId: string): boolean { + return this._commandRegistry.hasCommand(commandId); + } + registerCommand(command: ICommand): IDisposable { return this._registerCommand(command); } @@ -467,9 +488,3 @@ export function sequenceExecuteAsync( const promises = tasks.map((task) => () => commandService.executeCommand(task.id, task.params, options)); return sequenceAsync(promises); } - -export const NilCommand: ICommand = { - id: 'nil', - type: CommandType.COMMAND, - handler: () => true, -}; diff --git a/packages/rpc/src/services/remote-instance/remote-instance.service.ts b/packages/rpc/src/services/remote-instance/remote-instance.service.ts index c4f2f37ce8..83a06894cf 100644 --- a/packages/rpc/src/services/remote-instance/remote-instance.service.ts +++ b/packages/rpc/src/services/remote-instance/remote-instance.service.ts @@ -15,7 +15,7 @@ */ import type { IExecutionOptions, IMutationInfo, IWorkbookData } from '@univerjs/core'; -import { ICommandService, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; +import { ICommandService, ILogService, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { createIdentifier } from '@wendellhu/redi'; export interface IRemoteSyncMutationOptions extends IExecutionOptions { @@ -63,7 +63,8 @@ export interface IRemoteInstanceService { export class RemoteInstanceReplicaService implements IRemoteInstanceService { constructor( @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @ICommandService private readonly _commandService: ICommandService + @ICommandService private readonly _commandService: ICommandService, + @ILogService private readonly _logService: ILogService ) {} whenReady(): Promise { @@ -71,7 +72,13 @@ export class RemoteInstanceReplicaService implements IRemoteInstanceService { } async syncMutation(params: { mutationInfo: IMutationInfo }): Promise { - return this._commandService.syncExecuteCommand(params.mutationInfo.id, params.mutationInfo.params, { + const { id, params: mutationParams } = params.mutationInfo; + if (!this._commandService.hasCommand(id)) { + this._logService.debug('[RemoteInstanceReplicaService]', `command "${id}" not found. Skip sync mutation.`); + return true; + } + + return this._commandService.syncExecuteCommand(id, mutationParams, { onlyLocal: true, fromSync: true, });