diff --git a/src/index.js b/src/index.js index 233df73..969ccf9 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ const {servers} = require("./languageServers"); const {spawn} = require('child_process'); const url = require('url'); const WebSocket = require('ws'); +const net = require('net'); const verbose = argv.verbose || false; const { @@ -27,30 +28,35 @@ console.log("Started websocket server on port: ", _port); -wss.on('connection', (ws, req) => { - // ws://localhost:6005/gdscript?workspace=/yolo +wss.on('connection', async (ws, req) => { const address = url.parse(req.url, true); const pathname = address.pathname.substring(1); const qdata = address.query; const workspace = qdata.workspace; - handleLanguageConnection(ws, pathname, workspace); + await handleLanguageConnection(ws, pathname, workspace); + + ws.send(JSON.stringify({ + type: 'connected', + lang_id: pathname, + message: 'LSP Server connection established...', + })); }); -function handleLanguageConnection(ws, pathname, workspace) { +async function handleLanguageConnection(ws, pathname, workspace) { const server = servers.find(server => server.endpointName === pathname); - setupLanguageServer(ws, server, workspace); + await setupLanguageServer(ws, server, workspace); } -function setupLanguageServer(ws, server, workspace) { +async function setupLanguageServer(ws, server, workspace) { if (!server) return; const { reader, writer - } = startLanguageServer(server, workspace); + } = await startLanguageServer(server, workspace); server.writer = writer; @@ -81,13 +87,13 @@ function setupLanguageServer(ws, server, workspace) { }); } -function startLanguageServer(languageServer, workspace) { +async function startLanguageServer(languageServer, workspace) { const env = process.env; const args = languageServer.args.flat().map(arg => typeof arg === 'string' ? arg.replace('{workspace.path}', workspace || '') : arg ).filter(arg => arg !== ''); - const serverProcess = spawn(args[0], args.slice(1), { env, shell: true }); + const serverProcess = spawn(args[0], args.slice(1), { env }); serverProcess.stderr.on('data', data => { console.error(`${serverProcess.spawnfile} error: ${data}`); @@ -122,6 +128,17 @@ function startLanguageServer(languageServer, workspace) { throw 'The language server process does not have a valid stdin or stdout'; } + break; + case "tcp": + if (!languageServer.port) { + throw `Language Server Config for ${languageServer.endpointName} must have 'port' value...`; + } + + const socket = await connectWithRetry(languageServer.port); + + reader = new StreamMessageReader(socket); + writer = new StreamMessageWriter(socket); + break; default: throw 'Unknown connection type...'; @@ -133,6 +150,25 @@ function startLanguageServer(languageServer, workspace) { }; } +async function connectWithRetry(port, host = "localhost", retries = 5, delay = 1000) { + for (let attempt = 1; attempt <= retries; attempt++) { + try { + const socket = net.connect(port, host); + console.log(`Connected on attempt ${attempt}...`); + return socket; + } catch (err) { + console.warn(`Attempt ${attempt} failed`); + + if (attempt === retries) { + throw new Error(`Failed to connect after ${retries} retries...`); + } + + const wait = ms => new Promise(r => setTimeout(r, ms)); + await wait(delay * attempt); + } + } +} + function processMessage(message, ws, server) { if (message.params) { if (message.params.textDocument && message.params.textDocument.uri) { diff --git a/src/languageServers.js b/src/languageServers.js index f89ad60..926c6ef 100644 --- a/src/languageServers.js +++ b/src/languageServers.js @@ -16,11 +16,10 @@ exports.servers = [ ] ], nameEndsWith: ".gd", - connectionType: "ipc", + connectionType: "tcp", + port: 6005, relativePath: false }, { - - endpointName: "go", args: [ 'gopls', ['-mode=stdio', '-remote=auto']