@hydranium/glsp-server 1.0.0-next.31 → 1.0.0-next.315
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -88
- package/lib/browser/start-glsp-server-in-worker.d.ts +43 -42
- package/lib/browser/start-glsp-server-in-worker.d.ts.map +1 -1
- package/lib/browser/start-glsp-server-in-worker.js +62 -13
- package/lib/browser/start-glsp-server-in-worker.js.map +1 -1
- package/lib/command/diagram-edit-dropped-error.d.ts +31 -0
- package/lib/command/diagram-edit-dropped-error.d.ts.map +1 -0
- package/lib/command/diagram-edit-dropped-error.js +48 -0
- package/lib/command/diagram-edit-dropped-error.js.map +1 -0
- package/lib/command/hydranium-glsp-command-stack.d.ts +33 -0
- package/lib/command/hydranium-glsp-command-stack.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-command-stack.js +63 -0
- package/lib/command/hydranium-glsp-command-stack.js.map +1 -0
- package/lib/command/hydranium-glsp-operation-action-handler.d.ts +64 -0
- package/lib/command/hydranium-glsp-operation-action-handler.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-operation-action-handler.js +142 -0
- package/lib/command/hydranium-glsp-operation-action-handler.js.map +1 -0
- package/lib/command/hydranium-glsp-operation-command.d.ts +250 -0
- package/lib/command/hydranium-glsp-operation-command.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-operation-command.js +491 -0
- package/lib/command/hydranium-glsp-operation-command.js.map +1 -0
- package/lib/command/hydranium-glsp-recording-command.d.ts +26 -87
- package/lib/command/hydranium-glsp-recording-command.d.ts.map +1 -1
- package/lib/command/hydranium-glsp-recording-command.js +40 -117
- package/lib/command/hydranium-glsp-recording-command.js.map +1 -1
- package/lib/command/hydranium-glsp-undo-redo-action-handler.d.ts +23 -0
- package/lib/command/hydranium-glsp-undo-redo-action-handler.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-undo-redo-action-handler.js +41 -0
- package/lib/command/hydranium-glsp-undo-redo-action-handler.js.map +1 -0
- package/lib/command/index.d.ts +5 -0
- package/lib/command/index.d.ts.map +1 -1
- package/lib/command/index.js +5 -0
- package/lib/command/index.js.map +1 -1
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts +1 -1
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts.map +1 -1
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js +2 -2
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js.map +1 -1
- package/lib/dispatcher/server-action-dispatcher.d.ts +25 -24
- package/lib/dispatcher/server-action-dispatcher.d.ts.map +1 -1
- package/lib/dispatcher/server-action-dispatcher.js +38 -26
- package/lib/dispatcher/server-action-dispatcher.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts +35 -59
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts.map +1 -1
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.js +60 -71
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.js.map +1 -1
- package/lib/launcher/drop-notifications-to-gone-client.d.ts +23 -0
- package/lib/launcher/drop-notifications-to-gone-client.d.ts.map +1 -0
- package/lib/launcher/drop-notifications-to-gone-client.js +43 -0
- package/lib/launcher/drop-notifications-to-gone-client.js.map +1 -0
- package/lib/launcher/glsp-app-module.d.ts +1 -2
- package/lib/launcher/glsp-app-module.d.ts.map +1 -1
- package/lib/launcher/glsp-app-module.js.map +1 -1
- package/lib/launcher/glsp-connection-logger.d.ts +19 -0
- package/lib/launcher/glsp-connection-logger.d.ts.map +1 -0
- package/lib/launcher/glsp-connection-logger.js +24 -0
- package/lib/launcher/glsp-connection-logger.js.map +1 -0
- package/lib/launcher/glsp-server-overrides.d.ts +10 -8
- package/lib/launcher/glsp-server-overrides.d.ts.map +1 -1
- package/lib/launcher/glsp-server-overrides.js +25 -11
- package/lib/launcher/glsp-server-overrides.js.map +1 -1
- package/lib/launcher/hydranium-glsp-server.d.ts +60 -15
- package/lib/launcher/hydranium-glsp-server.d.ts.map +1 -1
- package/lib/launcher/hydranium-glsp-server.js +145 -22
- package/lib/launcher/hydranium-glsp-server.js.map +1 -1
- package/lib/launcher/index.d.ts +2 -0
- package/lib/launcher/index.d.ts.map +1 -1
- package/lib/launcher/index.js +5 -4
- package/lib/launcher/index.js.map +1 -1
- package/lib/logging/glsp-client-logger.d.ts +10 -6
- package/lib/logging/glsp-client-logger.d.ts.map +1 -1
- package/lib/logging/glsp-client-logger.js +14 -7
- package/lib/logging/glsp-client-logger.js.map +1 -1
- package/lib/messages/index.d.ts +11 -6
- package/lib/messages/index.d.ts.map +1 -1
- package/lib/messages/index.js +11 -6
- package/lib/messages/index.js.map +1 -1
- package/lib/node/start-glsp-server.d.ts +50 -15
- package/lib/node/start-glsp-server.d.ts.map +1 -1
- package/lib/node/start-glsp-server.js +97 -30
- package/lib/node/start-glsp-server.js.map +1 -1
- package/lib/state/abstract-hydranium-glsp-state.d.ts +326 -102
- package/lib/state/abstract-hydranium-glsp-state.d.ts.map +1 -1
- package/lib/state/abstract-hydranium-glsp-state.js +529 -139
- package/lib/state/abstract-hydranium-glsp-state.js.map +1 -1
- package/lib/state/diagram-status.d.ts +38 -0
- package/lib/state/diagram-status.d.ts.map +1 -0
- package/lib/state/diagram-status.js +27 -0
- package/lib/state/diagram-status.js.map +1 -0
- package/lib/state/full-text-hydranium-glsp-state.d.ts +22 -9
- package/lib/state/full-text-hydranium-glsp-state.d.ts.map +1 -1
- package/lib/state/full-text-hydranium-glsp-state.js +45 -18
- package/lib/state/full-text-hydranium-glsp-state.js.map +1 -1
- package/lib/state/hydranium-glsp-index.d.ts +40 -29
- package/lib/state/hydranium-glsp-index.d.ts.map +1 -1
- package/lib/state/hydranium-glsp-index.js +82 -45
- package/lib/state/hydranium-glsp-index.js.map +1 -1
- package/lib/state/hydranium-shared-core-services.d.ts +16 -29
- package/lib/state/hydranium-shared-core-services.d.ts.map +1 -1
- package/lib/state/hydranium-shared-core-services.js +15 -28
- package/lib/state/hydranium-shared-core-services.js.map +1 -1
- package/lib/state/index.d.ts +1 -0
- package/lib/state/index.d.ts.map +1 -1
- package/lib/state/index.js +1 -0
- package/lib/state/index.js.map +1 -1
- package/lib/state/model-ready-timeout-error.d.ts.map +1 -1
- package/lib/state/model-ready-timeout-error.js.map +1 -1
- package/lib/state/reconcile-source-model-write.d.ts +13 -27
- package/lib/state/reconcile-source-model-write.d.ts.map +1 -1
- package/lib/state/reconcile-source-model-write.js +44 -32
- package/lib/state/reconcile-source-model-write.js.map +1 -1
- package/lib/state/reconciling-multi-document-glsp-state.d.ts +125 -69
- package/lib/state/reconciling-multi-document-glsp-state.d.ts.map +1 -1
- package/lib/state/reconciling-multi-document-glsp-state.js +242 -100
- package/lib/state/reconciling-multi-document-glsp-state.js.map +1 -1
- package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts +36 -28
- package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts.map +1 -1
- package/lib/state/reconciling-transfer-hydranium-glsp-state.js +59 -42
- package/lib/state/reconciling-transfer-hydranium-glsp-state.js.map +1 -1
- package/lib/status/diagram-status-reporter.d.ts +44 -0
- package/lib/status/diagram-status-reporter.d.ts.map +1 -0
- package/lib/status/diagram-status-reporter.js +88 -0
- package/lib/status/diagram-status-reporter.js.map +1 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.d.ts +27 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.d.ts.map +1 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.js +52 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.js.map +1 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.d.ts +27 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.d.ts.map +1 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.js +53 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.js.map +1 -0
- package/lib/status/index.d.ts +12 -0
- package/lib/status/index.d.ts.map +1 -0
- package/lib/status/index.js +12 -0
- package/lib/status/index.js.map +1 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.d.ts +30 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.d.ts.map +1 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.js +47 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.js.map +1 -0
- package/lib/storage/hydranium-glsp-storage.d.ts +324 -143
- package/lib/storage/hydranium-glsp-storage.d.ts.map +1 -1
- package/lib/storage/hydranium-glsp-storage.js +569 -213
- package/lib/storage/hydranium-glsp-storage.js.map +1 -1
- package/lib/storage/index.d.ts +2 -1
- package/lib/storage/index.d.ts.map +1 -1
- package/lib/storage/index.js +2 -1
- package/lib/storage/index.js.map +1 -1
- package/lib/storage/save-delivery-policy.d.ts +51 -0
- package/lib/storage/save-delivery-policy.d.ts.map +1 -0
- package/lib/storage/{save-conflict-policy.js → save-delivery-policy.js} +7 -8
- package/lib/storage/save-delivery-policy.js.map +1 -0
- package/lib/submission/hydranium-glsp-submission-handler.d.ts +44 -4
- package/lib/submission/hydranium-glsp-submission-handler.d.ts.map +1 -1
- package/lib/submission/hydranium-glsp-submission-handler.js +82 -6
- package/lib/submission/hydranium-glsp-submission-handler.js.map +1 -1
- package/lib/testing/glsp-harness.d.ts +34 -7
- package/lib/testing/glsp-harness.d.ts.map +1 -1
- package/lib/testing/glsp-harness.js +47 -19
- package/lib/testing/glsp-harness.js.map +1 -1
- package/lib/validation/diagnostic-markers.d.ts +3 -3
- package/lib/validation/diagnostic-markers.d.ts.map +1 -1
- package/lib/validation/diagnostic-markers.js +1 -1
- package/lib/validation/diagnostic-markers.js.map +1 -1
- package/lib/validation/hydranium-glsp-model-validator.d.ts +1 -2
- package/lib/validation/hydranium-glsp-model-validator.d.ts.map +1 -1
- package/lib/validation/hydranium-glsp-model-validator.js +1 -1
- package/lib/validation/hydranium-glsp-model-validator.js.map +1 -1
- package/package.json +31 -52
- package/src/browser/start-glsp-server-in-worker.ts +79 -51
- package/src/command/diagram-edit-dropped-error.ts +51 -0
- package/src/command/hydranium-glsp-command-stack.ts +47 -0
- package/src/command/hydranium-glsp-operation-action-handler.ts +141 -0
- package/src/command/hydranium-glsp-operation-command.ts +602 -0
- package/src/command/hydranium-glsp-recording-command.ts +40 -121
- package/src/command/hydranium-glsp-undo-redo-action-handler.ts +29 -0
- package/src/command/index.ts +10 -0
- package/src/computed-bounds/hydranium-glsp-computed-bounds-action-handler.ts +2 -2
- package/src/dispatcher/server-action-dispatcher.ts +39 -31
- package/src/index.ts +1 -0
- package/src/launcher/abstract-hydranium-glsp-diagram-module.ts +79 -91
- package/src/launcher/drop-notifications-to-gone-client.ts +47 -0
- package/src/launcher/glsp-app-module.ts +1 -2
- package/src/launcher/glsp-connection-logger.ts +27 -0
- package/src/launcher/glsp-server-overrides.ts +27 -11
- package/src/launcher/hydranium-glsp-server.ts +153 -23
- package/src/launcher/index.ts +5 -4
- package/src/logging/glsp-client-logger.ts +16 -9
- package/src/messages/index.ts +16 -6
- package/src/node/start-glsp-server.ts +133 -40
- package/src/state/abstract-hydranium-glsp-state.ts +609 -154
- package/src/state/diagram-status.ts +41 -0
- package/src/state/full-text-hydranium-glsp-state.ts +46 -18
- package/src/state/hydranium-glsp-index.ts +85 -41
- package/src/state/hydranium-shared-core-services.ts +16 -29
- package/src/state/index.ts +1 -0
- package/src/state/reconcile-source-model-write.ts +51 -53
- package/src/state/reconciling-multi-document-glsp-state.ts +276 -102
- package/src/state/reconciling-transfer-hydranium-glsp-state.ts +67 -45
- package/src/status/diagram-status-reporter.ts +106 -0
- package/src/status/hydranium-glsp-request-model-action-handler.ts +43 -0
- package/src/status/hydranium-glsp-set-edit-mode-action-handler.ts +38 -0
- package/src/status/index.ts +12 -0
- package/src/storage/hydranium-glsp-request-save-model-action-handler.ts +40 -0
- package/src/storage/hydranium-glsp-storage.ts +647 -223
- package/src/storage/index.ts +2 -1
- package/src/storage/save-delivery-policy.ts +49 -0
- package/src/submission/hydranium-glsp-submission-handler.ts +91 -5
- package/src/testing/glsp-harness.ts +67 -25
- package/src/validation/diagnostic-markers.ts +3 -3
- package/src/validation/hydranium-glsp-model-validator.ts +4 -5
- package/lib/storage/save-conflict-policy.d.ts +0 -56
- package/lib/storage/save-conflict-policy.d.ts.map +0 -1
- package/lib/storage/save-conflict-policy.js.map +0 -1
- package/src/storage/save-conflict-policy.ts +0 -52
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import { type Action, type Logger, RequestAction } from '@eclipse-glsp/server';
|
|
11
|
+
import { describeError, describeErrorWithStack, isConflictError } from '@hydranium/protocol';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Thrown when the reconcile of a diagram edit's write dropped it: a foreign
|
|
15
|
+
* edit changed a field the edit writes. Declined by design rather than failed,
|
|
16
|
+
* and the reconcile has logged it, so whoever ends it tells the client without
|
|
17
|
+
* logging it again. It never crosses a wire, so it carries no error code.
|
|
18
|
+
*/
|
|
19
|
+
export class DiagramEditDroppedError extends Error {
|
|
20
|
+
constructor(message: string) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = 'DiagramEditDroppedError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Whether `error` is a {@link DiagramEditDroppedError}, by name, so one thrown
|
|
28
|
+
* by another installed copy of this package counts too.
|
|
29
|
+
*/
|
|
30
|
+
export function isDiagramEditDroppedError(error: unknown): error is DiagramEditDroppedError {
|
|
31
|
+
return error instanceof Error && error.name === 'DiagramEditDroppedError';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Log an action that failed, once, at the level of what happened: a dropped
|
|
36
|
+
* edit at `debug`, since its reconcile has logged it, a conflict at `warn`
|
|
37
|
+
* naming its versions, since it was declined, and anything else at `error`.
|
|
38
|
+
* A request is named by its id too, which its client's reject carries.
|
|
39
|
+
*/
|
|
40
|
+
export function logActionFailure(logger: Logger, action: Action, error: unknown): void {
|
|
41
|
+
const named = `'${action.kind}'${RequestAction.is(action) ? ` (${action.requestId})` : ''}`;
|
|
42
|
+
if (isDiagramEditDroppedError(error)) {
|
|
43
|
+
logger.debug(`Could not process action ${named}: ${describeError(error)}`);
|
|
44
|
+
} else if (isConflictError(error)) {
|
|
45
|
+
logger.warn(
|
|
46
|
+
`Could not process action ${named}: ${describeError(error)} (model v${error.baseVersion} / text v${error.actualVersion})`
|
|
47
|
+
);
|
|
48
|
+
} else {
|
|
49
|
+
logger.error(`Could not process action ${named}: ${describeErrorWithStack(error)}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import { DefaultCommandStack, ModelState } from '@eclipse-glsp/server';
|
|
11
|
+
import { type ServerSharedServices } from '@hydranium/core';
|
|
12
|
+
import { inject, injectable } from 'inversify';
|
|
13
|
+
import { HydraniumTypes } from '../state/hydranium-shared-core-services.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* GLSP's command stack with the diagram's dirty state read from the text store:
|
|
17
|
+
* dirty while any document the diagram's client session has open differs from
|
|
18
|
+
* its file, as the store last knew the file. Undo and redo are GLSP's.
|
|
19
|
+
*
|
|
20
|
+
* GLSP's own answer counts the diagram's commands since its last save, so it
|
|
21
|
+
* misses every change the diagram did not make: another client's unsaved edit
|
|
22
|
+
* leaves it clean, and a save it did not make of a document other than the
|
|
23
|
+
* diagram's own leaves it dirty. Every `SetDirtyStateAction` GLSP sends reads
|
|
24
|
+
* this answer.
|
|
25
|
+
*/
|
|
26
|
+
@injectable()
|
|
27
|
+
export class HydraniumGlspCommandStack extends DefaultCommandStack {
|
|
28
|
+
@inject(ModelState) protected readonly modelState!: ModelState;
|
|
29
|
+
@inject(HydraniumTypes.SharedCoreServices) protected readonly sharedServices!: ServerSharedServices;
|
|
30
|
+
|
|
31
|
+
override get isDirty(): boolean {
|
|
32
|
+
const textDocuments = this.sharedServices.workspace.TextDocuments;
|
|
33
|
+
const clientId = this.modelState.clientId;
|
|
34
|
+
return textDocuments.openDocuments().some(open => open.clients.includes(clientId) && textDocuments.isDirty(open.uri));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Lifted from `@eclipse-glsp/server` 2.7.0's `DefaultCommandStack.handleError`
|
|
39
|
+
* without its `error` line: the failure is rethrown, and whoever ends it
|
|
40
|
+
* logs it. The accompanying test pins upstream's source.
|
|
41
|
+
*/
|
|
42
|
+
protected override handleError(error: unknown): never {
|
|
43
|
+
this.flush();
|
|
44
|
+
this.logger.debug('A command failed; the command stack was flushed');
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
type Action,
|
|
12
|
+
ActionDispatcher,
|
|
13
|
+
type AnyObject,
|
|
14
|
+
GLSPClientProxy,
|
|
15
|
+
GLSPServerError,
|
|
16
|
+
Logger,
|
|
17
|
+
MessageAction,
|
|
18
|
+
type Operation,
|
|
19
|
+
OperationActionHandler,
|
|
20
|
+
type OperationHandler
|
|
21
|
+
} from '@eclipse-glsp/server';
|
|
22
|
+
import { describeErrorWithStack } from '@hydranium/protocol';
|
|
23
|
+
import { inject, injectable } from 'inversify';
|
|
24
|
+
import { logActionFailure } from './diagram-edit-dropped-error.js';
|
|
25
|
+
import { HydraniumGlspOperationCommand, openOperationOf, runOperation } from './hydranium-glsp-operation-command.js';
|
|
26
|
+
import { type HydraniumGlspRecordingState } from './hydranium-glsp-recording-command.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* GLSP's operation action handler, running each operation as a
|
|
30
|
+
* {@link HydraniumGlspOperationCommand} inside the state's `runExclusive`,
|
|
31
|
+
* which covers the operation, its write, the command-stack push and the
|
|
32
|
+
* submit, so neither another operation, an undo nor the storage's capture
|
|
33
|
+
* lands between them.
|
|
34
|
+
*
|
|
35
|
+
* An operation dispatched while another is open, as a handler's plain
|
|
36
|
+
* `dispatch` does, is queued behind it and its dispatch resolves at once;
|
|
37
|
+
* awaited inside the open operation, it would wait for the operation awaiting
|
|
38
|
+
* it. It writes, pushes and submits on its own, and a failure is reported to
|
|
39
|
+
* the client as GLSP reports a failed client action.
|
|
40
|
+
*
|
|
41
|
+
* Only operations are queued that way, and only while one is open, its undo's
|
|
42
|
+
* side effects included. Code running inside the boundary otherwise must not
|
|
43
|
+
* dispatch an operation and await it: a GModel factory or a submit after an
|
|
44
|
+
* operation, an undo's write and submit, the storage's render. Nor may any code
|
|
45
|
+
* inside the boundary await a dispatched undo, redo or model request, which
|
|
46
|
+
* take the boundary themselves. Each waits for the section awaiting it.
|
|
47
|
+
*/
|
|
48
|
+
@injectable()
|
|
49
|
+
export class HydraniumGlspOperationActionHandler extends OperationActionHandler {
|
|
50
|
+
declare protected modelState: HydraniumGlspRecordingState<AnyObject>;
|
|
51
|
+
@inject(ActionDispatcher) protected readonly actionDispatcher!: ActionDispatcher;
|
|
52
|
+
@inject(Logger) protected readonly logger!: Logger;
|
|
53
|
+
@inject(GLSPClientProxy) protected readonly clientProxy!: GLSPClientProxy;
|
|
54
|
+
|
|
55
|
+
protected override executeHandler(operation: Operation, handler: OperationHandler): Promise<Action[]> {
|
|
56
|
+
const queued = openOperationOf(this.modelState) !== undefined;
|
|
57
|
+
const run = this.modelState.runExclusive(() => this.runOperation(operation, handler));
|
|
58
|
+
if (!queued) {
|
|
59
|
+
return run;
|
|
60
|
+
}
|
|
61
|
+
run.then(
|
|
62
|
+
actions => this.deliverQueued(actions),
|
|
63
|
+
(error: unknown) => this.reportFailure(operation, error)
|
|
64
|
+
);
|
|
65
|
+
return Promise.resolve([]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Run `operation`; push it when its command was written, and submit the
|
|
70
|
+
* model when it executed one, written or dropped.
|
|
71
|
+
*/
|
|
72
|
+
protected async runOperation(operation: Operation, handler: OperationHandler): Promise<Action[]> {
|
|
73
|
+
// A queued operation can find the diagram read-only by the time it runs.
|
|
74
|
+
if (this.modelState.isReadonly) {
|
|
75
|
+
return [
|
|
76
|
+
MessageAction.create(`Server is in readonly-mode! Could not execute operation: ${operation.kind}`, { severity: 'WARNING' })
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
const command = new HydraniumGlspOperationCommand(this.modelState);
|
|
80
|
+
const outcome = await runOperation(command, () => handler.execute(operation));
|
|
81
|
+
if (outcome === 'none') {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
if (outcome === 'executed') {
|
|
85
|
+
await this.executeCommand(command);
|
|
86
|
+
}
|
|
87
|
+
return this.submitModel();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Deliver what a queued operation answered: a message straight to the
|
|
92
|
+
* client, as {@link reportFailure} sends one, the rest through the
|
|
93
|
+
* dispatcher. A failure to deliver is logged, not reported as the
|
|
94
|
+
* operation's.
|
|
95
|
+
*/
|
|
96
|
+
protected deliverQueued(actions: Action[]): void {
|
|
97
|
+
const messages = actions.filter(action => MessageAction.is(action));
|
|
98
|
+
messages.forEach(message => this.sendToClient(message));
|
|
99
|
+
this.actionDispatcher
|
|
100
|
+
.dispatchAll(actions.filter(action => !MessageAction.is(action)))
|
|
101
|
+
.catch((error: unknown) =>
|
|
102
|
+
this.logger.warn(`Could not deliver the result of a queued operation: ${describeErrorWithStack(error)}`)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Log `error` with {@link logActionFailure}, as the server logs a failed
|
|
108
|
+
* action, and send the client the error message GLSP sends for one. A
|
|
109
|
+
* queued operation that fails once its diagram has closed, which the
|
|
110
|
+
* storage's dispose marks by clearing the state's session, is logged at
|
|
111
|
+
* `debug` and told to no client, as the server treats an ended session.
|
|
112
|
+
*/
|
|
113
|
+
protected reportFailure(operation: Operation, error: unknown): void {
|
|
114
|
+
// Queued only after a load registered the session, so none now means the diagram has closed.
|
|
115
|
+
if (this.modelState.modelSession === undefined) {
|
|
116
|
+
this.logger.debug(`Operation '${operation.kind}' ended with its diagram: ${describeErrorWithStack(error)}`);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
logActionFailure(this.logger, operation, error);
|
|
120
|
+
let message = `Could not process action: '${operation.kind}`;
|
|
121
|
+
let details = error instanceof Error ? error.toString() : String(error);
|
|
122
|
+
if (error instanceof GLSPServerError) {
|
|
123
|
+
details = String(error.cause);
|
|
124
|
+
message = error.message;
|
|
125
|
+
}
|
|
126
|
+
this.sendToClient(MessageAction.create(message, { severity: 'ERROR', details }));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Send `action` straight to the client, as GLSP's server sends a failed
|
|
131
|
+
* action's message. Sent through the dispatcher instead, an action of a
|
|
132
|
+
* kind the client registered no handler for is rejected.
|
|
133
|
+
*/
|
|
134
|
+
protected sendToClient(action: Action): void {
|
|
135
|
+
try {
|
|
136
|
+
this.clientProxy.process({ clientId: this.modelState.clientId, action });
|
|
137
|
+
} catch (error: unknown) {
|
|
138
|
+
this.logger.warn(`Could not send '${action.kind}' to the client: ${describeErrorWithStack(error)}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|