/
githubmirror
/
brackets
Обзор
Документация
Войти
/
githubmirror
/
brackets
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
release-1.14
src/languageTools/ClientLoader.js
179 строк
8 KB
Shubham Yadav
Reinitiate tooling service on Node process crash (#14724)
25 апр 2019, 07:19
25 апр 2019, 07:19
6db26a2
Код
Авторство
О чём код?
/* * Copyright (c) 2019 - present Adobe. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ /*eslint no-console: 0*/ /*eslint max-len: ["error", { "code": 200 }]*/ define(function (require, exports, module) { "use strict"; var ToolingInfo = JSON.parse(require("text!languageTools/ToolingInfo.json")), NodeDomain = require("utils/NodeDomain"), FileUtils = require("file/FileUtils"), EventDispatcher = require("utils/EventDispatcher"), BracketsToNodeInterface = require("languageTools/BracketsToNodeInterface").BracketsToNodeInterface; EventDispatcher.makeEventDispatcher(exports); //Register paths required for Language Client and also register default brackets capabilities. var _bracketsPath = FileUtils.getNativeBracketsDirectoryPath(); // The native directory path ends with either "test" or "src". _bracketsPath = _bracketsPath.replace(/\/test$/, "/src"); // convert from "test" to "src" var _modulePath = FileUtils.getNativeModuleDirectoryPath(module), _nodePath = "node/RegisterLanguageClientInfo", _domainPath = [_bracketsPath, _modulePath, _nodePath].join("/"), clientInfoDomain = null, clientInfoLoadedPromise = null, //Clients that have to be loaded once the LanguageClient info is successfully loaded on the //node side. pendingClientsToBeLoaded = []; function syncPrefsWithDomain(languageToolsPrefs) { if (clientInfoDomain) { clientInfoDomain.exec("syncPreferences", languageToolsPrefs); } } function _createNodeDomain(domainName, domainPath) { return new NodeDomain(domainName, domainPath); } function loadLanguageClientDomain(clientName, domainPath) { //generate a random hash name for the domain, this is the client id var domainName = clientName, result = $.Deferred(), languageClientDomain = _createNodeDomain(domainName, domainPath); if (languageClientDomain) { languageClientDomain.promise() .done(function () { console.log(domainPath + " domain successfully created"); result.resolve(languageClientDomain); }) .fail(function (err) { console.error(domainPath + " domain could not be created."); result.reject(); }); } else { console.error(domainPath + " domain could not be created."); result.reject(); } return result; } function createNodeInterfaceForDomain(languageClientDomain) { var nodeInterface = new BracketsToNodeInterface(languageClientDomain); return nodeInterface; } function _clientLoader(clientName, clientFilePath, clientPromise) { loadLanguageClientDomain(clientName, clientFilePath) .then(function (languageClientDomain) { var languageClientInterface = createNodeInterfaceForDomain(languageClientDomain); clientPromise.resolve({ name: clientName, interface: languageClientInterface }); }, clientPromise.reject); } function initiateLanguageClient(clientName, clientFilePath) { var result = $.Deferred(); //Only load clients after the LanguageClient Info has been initialized if (!clientInfoLoadedPromise || clientInfoLoadedPromise.state() === "pending") { var pendingClient = { load: _clientLoader.bind(null, clientName, clientFilePath, result) }; pendingClientsToBeLoaded.push(pendingClient); } else { _clientLoader(clientName, clientFilePath, result); } return result; } /** * This function passes Brackets's native directory path as well as the tooling commands * required by the LanguageClient node module. This information is then maintained in memory * in the node process server for succesfully loading and functioning of all language clients * since it is a direct dependency. */ function sendLanguageClientInfo() { //Init node with Information required by Language Client clientInfoLoadedPromise = clientInfoDomain.exec("initialize", _bracketsPath, ToolingInfo); function logInitializationError() { console.error("Failed to Initialize LanguageClient Module Information."); } //Attach success and failure function for the clientInfoLoadedPromise clientInfoLoadedPromise.then(function (success) { if (!success) { logInitializationError(); return; } if (Array.isArray(pendingClientsToBeLoaded)) { pendingClientsToBeLoaded.forEach(function (pendingClient) { pendingClient.load(); }); } else { exports.trigger("languageClientModuleInitialized"); } pendingClientsToBeLoaded = null; }, function () { logInitializationError(); }); } /** * This function starts a domain which initializes the LanguageClient node module * required by the Language Server Protocol framework in Brackets. All the LSP clients * can only be successfully initiated once this domain has been successfully loaded and * the LanguageClient info initialized. Refer to sendLanguageClientInfo for more. */ function initDomainAndHandleNodeCrash() { clientInfoDomain = new NodeDomain("LanguageClientInfo", _domainPath); //Initialize LanguageClientInfo once the domain has successfully loaded. clientInfoDomain.promise().done(function () { sendLanguageClientInfo(); //This is to handle the node failure. If the node process dies, we get an on close //event on the websocket connection object. Brackets then spawns another process and //restablishes the connection. Once the connection is restablished we send reinitialize //the LanguageClient info. clientInfoDomain.connection.on("close", function (event, reconnectedPromise) { reconnectedPromise.done(sendLanguageClientInfo); }); }).fail(function (err) { console.error("ClientInfo domain could not be loaded: ", err); }); } initDomainAndHandleNodeCrash(); exports.initiateLanguageClient = initiateLanguageClient; exports.syncPrefsWithDomain = syncPrefsWithDomain; });