@eclipse-glsp/client
Version:
A sprotty-based client for GLSP
186 lines • 8.79 kB
JavaScript
"use strict";
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.GLSPActionDispatcher = void 0;
/********************************************************************************
* Copyright (c) 2019-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
********************************************************************************/
const sprotty_1 = require("@eclipse-glsp/sprotty");
const inversify_1 = require("inversify");
const action_handler_registry_1 = require("./action-handler-registry");
const glsp_model_source_1 = require("./model/glsp-model-source");
const model_initialization_constraint_1 = require("./model/model-initialization-constraint");
let GLSPActionDispatcher = class GLSPActionDispatcher extends sprotty_1.ActionDispatcher {
constructor() {
super(...arguments);
this.timeouts = new Map();
this.initializedConstraint = false;
this.postUpdateQueue = [];
this.initializeDeferred = new sprotty_1.Deferred();
}
initialize() {
if (!this.initialized) {
this.initialized = this.initializeDeferred.promise;
this.doInitialize();
}
return this.initialized;
}
async doInitialize() {
try {
if (this.actionHandlerRegistry instanceof action_handler_registry_1.GLSPActionHandlerRegistry) {
this.actionHandlerRegistry.initialize();
}
this.handleAction(sprotty_1.SetModelAction.create(sprotty_1.EMPTY_ROOT)).catch(() => {
/* Logged in handleAction method */
});
this.startModelInitialization();
this.initializeDeferred.resolve();
}
catch (error) {
this.initializeDeferred.reject(error);
}
}
startModelInitialization() {
if (!this.initializedConstraint) {
this.logger.log(this, 'Starting model initialization mode');
this.initializationConstraint.onInitialized(() => this.logger.log(this, 'Model initialization completed'));
this.initializedConstraint = true;
}
}
onceModelInitialized() {
return this.initializationConstraint.onInitialized();
}
hasHandler(action) {
return this.actionHandlerRegistry.get(action.kind).length > 0;
}
/**
* Processes all given actions, by dispatching them to the corresponding handlers, after the model initialization is completed.
*
* @param actions The actions that should be dispatched after the model initialization
*/
dispatchOnceModelInitialized(...actions) {
this.initializationConstraint.onInitialized(() => this.dispatchAll(actions));
}
/**
* Processes all given actions, by dispatching them to the corresponding handlers, after the next model update.
* The given actions are queued until the next model update cycle has been completed i.e.
* the `EditorContextService.onModelRootChanged` event is triggered.
*
* @param actions The actions that should be dispatched after the next model update
*/
dispatchAfterNextUpdate(...actions) {
this.postUpdateQueue.push(...actions);
}
modelRootChanged(_root) {
if (this.postUpdateQueue.length === 0) {
return;
}
const toDispatch = [...this.postUpdateQueue];
this.postUpdateQueue = [];
this.dispatchAll(toDispatch);
}
async dispatch(action) {
const result = await super.dispatch(action);
this.initializationConstraint.notifyDispatched(action);
return result;
}
handleAction(action) {
if (sprotty_1.ResponseAction.hasValidResponseId(action)) {
// clear timeout
const timeout = this.timeouts.get(action.responseId);
if (timeout !== undefined) {
clearTimeout(timeout);
this.timeouts.delete(action.responseId);
}
// Check if we have a pending request for the response.
// If not the we clear the responseId => action will be dispatched normally
const deferred = this.requests.get(action.responseId);
if (deferred === undefined) {
action.responseId = '';
}
}
if (!this.hasHandler(action) && glsp_model_source_1.OptionalAction.is(action)) {
return Promise.resolve();
}
return super.handleAction(action);
}
request(action) {
if (!action.requestId && action.requestId === '') {
// No request id has been specified. So we use a generated one.
action.requestId = sprotty_1.RequestAction.generateRequestId();
}
return super.request(action);
}
/**
* Dispatch a request and waits for a response until the timeout given in `timeoutMs` has
* been reached. The returned promise is resolved when a response with matching identifier
* is dispatched or when the timeout has been reached. That response is _not_ passed to the
* registered action handlers. Instead, it is the responsibility of the caller of this method
* to handle the response properly. For example, it can be sent to the registered handlers by
* passing it again to the `dispatch` method.
* If `rejectOnTimeout` is set to false (default) the returned promise will be resolved with
* no value, otherwise it will be rejected.
*/
requestUntil(action, timeoutMs = 2000, rejectOnTimeout = false) {
if (!action.requestId && action.requestId === '') {
// No request id has been specified. So we use a generated one.
action.requestId = sprotty_1.RequestAction.generateRequestId();
}
const requestId = action.requestId;
const timeout = setTimeout(() => {
const deferred = this.requests.get(requestId);
if (deferred !== undefined) {
// cleanup
clearTimeout(timeout);
this.requests.delete(requestId);
const notification = 'Request ' + requestId + ' (' + action + ') time out after ' + timeoutMs + 'ms.';
if (rejectOnTimeout) {
deferred.reject(notification);
}
else {
this.logger.info(this, notification);
deferred.resolve();
}
}
}, timeoutMs);
this.timeouts.set(requestId, timeout);
return super.request(action);
}
};
exports.GLSPActionDispatcher = GLSPActionDispatcher;
__decorate([
(0, inversify_1.inject)(model_initialization_constraint_1.ModelInitializationConstraint),
__metadata("design:type", model_initialization_constraint_1.ModelInitializationConstraint)
], GLSPActionDispatcher.prototype, "initializationConstraint", void 0);
__decorate([
(0, inversify_1.inject)(sprotty_1.ActionHandlerRegistry),
__metadata("design:type", sprotty_1.ActionHandlerRegistry)
], GLSPActionDispatcher.prototype, "actionHandlerRegistry", void 0);
__decorate([
(0, inversify_1.inject)(sprotty_1.TYPES.ActionHandlerRegistryProvider),
__metadata("design:type", Function)
], GLSPActionDispatcher.prototype, "actionHandlerRegistryProvider", void 0);
exports.GLSPActionDispatcher = GLSPActionDispatcher = __decorate([
(0, inversify_1.injectable)()
], GLSPActionDispatcher);
//# sourceMappingURL=action-dispatcher.js.map