@eclipse-glsp/client
Version:
A sprotty-based client for GLSP
195 lines • 8.79 kB
JavaScript
"use strict";
/********************************************************************************
* Copyright (c) 2023-2024 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GLSPModelSource = exports.OptionalAction = exports.ServerAction = void 0;
const sprotty_1 = require("@eclipse-glsp/sprotty");
const inversify_1 = require("inversify");
var ServerAction;
(function (ServerAction) {
function is(object) {
return sprotty_1.Action.is(object) && '__receivedFromServer' in object && object.__receivedFromServer === true;
}
ServerAction.is = is;
/**
* Mark the given action as {@link ServerAction} by attaching the "__receivedFromServer" property
* @param action The action that should be marked as server action
*/
function mark(action) {
action.__receivedFromServer = true;
}
ServerAction.mark = mark;
})(ServerAction || (exports.ServerAction = ServerAction = {}));
var OptionalAction;
(function (OptionalAction) {
function is(object) {
return sprotty_1.Action.is(object) && '__skipErrorIfNoHandler' in object && object.__skipErrorIfNoHandler === true;
}
OptionalAction.is = is;
/**
* Mark the given action as {@link OptionalAction} by attaching the "__skipErrorIfNoHandler" property
* @param action The action that should be marked as optional action
*/
function mark(action) {
action.__skipErrorIfNoHandler = true;
return action;
}
OptionalAction.mark = mark;
})(OptionalAction || (exports.OptionalAction = OptionalAction = {}));
/**
* Central component for enabling the client-server action flow with the help of an underlying {@link GLSPClient}.
* Handles & forwards actions that are intended for the GLSP server. In addition, it handles {@link ActionMessage}s received
* from the server and dispatches the corresponding actions locally.
*
* Note that in sprotty a {@link ModelSource} is serving the model to the event cycle and
* is used to commit the local (i.e. client-side) model back to the source.
* However, in GLSP the update flow is reversed meaning that changes to the source model are applied
* on the server side and then an update is sent to the client.
*/
let GLSPModelSource = class GLSPModelSource extends sprotty_1.ModelSource {
constructor() {
super(...arguments);
this.toDispose = new sprotty_1.DisposableCollection();
}
get diagramType() {
return this.options.diagramType;
}
get sourceUri() {
return this.options.sourceUri;
}
/**
* Configure forwarding of server-handled actions to the given {@link GLSPClient} and
* handling of action received from the `GLSPClient` (i.e. server). It is expected that the
* given GLSP client has already been initialized.
* @param glspClient The GLSP to use.
* @throws An error if the given `GLSPClient` has not been initialized yet or if the set of server handled
* action kinds could not be derived from the initialize result
*/
configure(glspClient) {
this.glspClient = glspClient;
if (!glspClient.initializeResult) {
throw new Error('Could not configure model source. The GLSP client is not initialized yet!');
}
const initializeParams = this.createInitializeClientSessionParameters(glspClient.initializeResult);
this.configureServeActions(glspClient.initializeResult);
this.toDispose.push(glspClient.onActionMessage(message => this.messageReceived(message), this.clientId), sprotty_1.Disposable.create(() => glspClient.disposeClientSession(this.createDisposeClientSessionParameters())));
return glspClient.initializeClientSession(initializeParams);
}
createInitializeClientSessionParameters(_initializeResult) {
const clientActionKinds = this.registry.getHandledActionKinds();
return {
clientSessionId: this.clientId,
clientActionKinds,
diagramType: this.diagramType
};
}
createDisposeClientSessionParameters() {
return {
clientSessionId: this.clientId
};
}
configureServeActions(initializeResult) {
const serverActions = initializeResult.serverActions[this.diagramType];
if ((serverActions === null || serverActions === void 0 ? void 0 : serverActions.length) === 0) {
throw new Error(`No server-handled actions could be derived from the initialize result for diagramType: ${this.diagramType}!`);
}
serverActions.forEach(action => this.registry.register(action, this));
}
messageReceived(message) {
if (this.clientId !== message.clientId) {
return;
}
const action = message.action;
ServerAction.mark(action);
this.logger.log(this, 'receiving', action);
this.actionDispatcher.dispatch(action);
}
initialize(registry) {
var _a;
// Registering actions here is discouraged and it's recommended
// to implemented dedicated action handlers.
if (!this.clientId) {
this.clientId = (_a = this.options.clientId) !== null && _a !== void 0 ? _a : this.viewerOptions.baseDiv;
}
this.registry = registry;
}
handle(action) {
// Handling additional actions here is discouraged and it's recommended
// to implemented dedicated action handlers.
if (this.shouldForwardToServer(action)) {
this.forwardToServer(action);
}
}
forwardToServer(action) {
const message = {
clientId: this.clientId,
action: action
};
this.logger.log(this, 'sending', message);
if (this.glspClient) {
this.glspClient.sendActionMessage(message);
}
else {
throw new Error('GLSPClient is not connected');
}
}
shouldForwardToServer(action) {
return !ServerAction.is(action);
}
commitModel(newRoot) {
/* In GLSP the model update flow is server-driven. i.e. changes to the graphical model are applied
* on server-side an only the server can issue a model update.
* The internal/local model should never be committed back to the model source i.e. GLSP server.
* => no-op implementation that simply returns the `newRoot`
*/
this._currentRoot = newRoot;
return newRoot;
}
get model() {
return this._currentRoot;
}
dispose() {
this.toDispose.dispose();
}
};
exports.GLSPModelSource = GLSPModelSource;
__decorate([
(0, inversify_1.inject)(sprotty_1.TYPES.ILogger),
__metadata("design:type", Object)
], GLSPModelSource.prototype, "logger", void 0);
__decorate([
(0, inversify_1.inject)(sprotty_1.TYPES.IDiagramOptions),
__metadata("design:type", Object)
], GLSPModelSource.prototype, "options", void 0);
__decorate([
(0, inversify_1.preDestroy)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], GLSPModelSource.prototype, "dispose", null);
exports.GLSPModelSource = GLSPModelSource = __decorate([
(0, inversify_1.injectable)()
], GLSPModelSource);
//# sourceMappingURL=glsp-model-source.js.map