1- /* eslint-disable @typescript-eslint/no-explicit-any */
21/* eslint-disable class-methods-use-this */
32/* eslint-disable global-require */
43/*---------------------------------------------------------------------------------------------
54 * Copyright (C) 2023 Posit Software, PBC. All rights reserved.
65 *--------------------------------------------------------------------------------------------*/
76
8- import { Socket } from 'net' ;
97import * as path from 'path' ;
108import * as fs from 'fs' ;
119// eslint-disable-next-line import/no-unresolved
1210import * as positron from 'positron' ;
1311import * as vscode from 'vscode' ;
1412import * as crypto from 'crypto' ;
15- import { Disposable , DocumentFilter , LanguageClient , LanguageClientOptions , ServerOptions , StreamInfo } from 'vscode-languageclient/node' ;
13+ import { Disposable , DocumentFilter , LanguageClientOptions } from 'vscode-languageclient/node' ;
1614
1715import { compare } from 'semver' ;
1816import { EXTENSION_ROOT_DIR , PYTHON_LANGUAGE } from '../../common/constants' ;
1917import { IConfigurationService , IInstaller , InstallerResponse , Product , Resource } from '../../common/types' ;
2018import { InstallOptions } from '../../common/installer/types' ;
2119import { IInterpreterService } from '../../interpreter/contracts' ;
2220import { IServiceContainer } from '../../ioc/types' ;
23- import { traceError , traceVerbose } from '../../logging' ;
21+ import { traceVerbose } from '../../logging' ;
2422import { PythonEnvironment } from '../../pythonEnvironments/info' ;
2523import { PythonVersion } from '../../pythonEnvironments/info/pythonVersion' ;
26- import { ProgressReporting } from '../progress' ;
2724import { ILanguageServerProxy } from '../types' ;
2825import { PythonLanguageRuntime } from './pythonLanguageRuntime' ;
2926import { JupyterAdapterApi } from '../../jupyter-adapter.d'
@@ -42,8 +39,6 @@ export class PositronJediLanguageServerProxy implements ILanguageServerProxy {
4239
4340 private readonly disposables : Disposable [ ] = [ ] ;
4441
45- private readonly languageClients : LanguageClient [ ] = [ ] ;
46-
4742 private extensionVersion : string | undefined ;
4843
4944 private readonly installer : IInstaller ;
@@ -119,16 +114,6 @@ export class PositronJediLanguageServerProxy implements ILanguageServerProxy {
119114 const r = this . disposables . shift ( ) ! ;
120115 r . dispose ( ) ;
121116 }
122-
123- // Dispose of any language clients
124- for ( const client of this . languageClients ) {
125- try {
126- await client . stop ( ) ;
127- await client . dispose ( ) ;
128- } catch ( ex ) {
129- traceError ( 'Stopping language client failed' , ex ) ;
130- }
131- }
132117 }
133118
134119 public dispose ( ) : void {
@@ -242,17 +227,7 @@ export class PositronJediLanguageServerProxy implements ILanguageServerProxy {
242227
243228 // Create an adapter for the kernel as our language runtime
244229 const runtime = new PythonLanguageRuntime (
245- kernelSpec , metadata , jupyterAdapterApi ) ;
246-
247- runtime . onDidChangeRuntimeState ( ( state ) => {
248- if ( state === positron . RuntimeState . Ready ) {
249- jupyterAdapterApi . findAvailablePort ( [ ] , 25 ) . then ( ( port : number ) => {
250- runtime . emitJupyterLog ( `Starting Positron LSP server on port ${ port } ` ) ;
251- runtime . startPositronLsp ( `127.0.0.1:${ port } ` ) ;
252- this . startClient ( options , port ) . ignoreErrors ( ) ;
253- } ) ;
254- }
255- } ) ;
230+ kernelSpec , metadata , jupyterAdapterApi , options ) ;
256231
257232 // Register our language runtime provider
258233 return positron . runtime . registerLanguageRuntime ( runtime ) ;
@@ -295,77 +270,7 @@ export class PositronJediLanguageServerProxy implements ILanguageServerProxy {
295270 return `${ info . major } .${ info . minor } .${ info . patch } ` ;
296271 }
297272
298- /**
299- * Start the language client
300- */
301- private async startClient ( clientOptions : LanguageClientOptions , port : number ) : Promise < void > {
302-
303- // Configure language client to connect to LSP via TCP on start
304- const serverOptions : ServerOptions = async ( ) => this . getServerOptions ( port ) ;
305- const client = new LanguageClient ( PYTHON_LANGUAGE , 'Positron Python Jedi' , serverOptions , clientOptions ) ;
306- this . registerHandlers ( client ) ;
307- await client . start ( ) ;
308- this . languageClients . push ( client ) ;
309- }
310-
311- /**
312- * An async function used by the LanguageClient to establish a connection to the LSP on start.
313- * Several attempts to connect are made given recently spawned servers may not be ready immediately
314- * for client connections.
315- * @param port the LSP port
316- */
317- private async getServerOptions ( port : number ) : Promise < StreamInfo > {
318-
319- const delay = ( ms : number ) => new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
320- const maxAttempts = 20 ;
321- const baseDelay = 50 ;
322- const multiplier = 1.5 ;
323-
324- for ( let attempt = 0 ; attempt < maxAttempts ; attempt += 1 ) {
325- // Retry up to five times then start to back-off
326- const interval = attempt < 6 ? baseDelay : baseDelay * multiplier * attempt ;
327- if ( attempt > 0 ) {
328- await delay ( interval ) ;
329- }
330-
331- try {
332- // Try to connect to LSP port
333- const socket : Socket = await this . tryToConnect ( port ) ;
334- return { reader : socket , writer : socket } ;
335- } catch ( error : any ) {
336- if ( error ?. code === 'ECONNREFUSED' ) {
337- traceVerbose ( `Error '${ error . message } ' on connection attempt '${ attempt } ' to Jedi LSP on port '${ port } ', will retry` ) ;
338- } else {
339- throw error ;
340- }
341- }
342- }
343-
344- throw new Error ( `Failed to create TCP connection to Jedi LSP on port ${ port } after multiple attempts` ) ;
345- }
346-
347- /**
348- * Attempts to establish a TCP socket connection to the given port
349- * @param port the server port to connect to
350- */
351- private async tryToConnect ( port : number ) : Promise < Socket > {
352- return new Promise ( ( resolve , reject ) => {
353- const socket = new Socket ( ) ;
354- socket . on ( 'ready' , ( ) => {
355- resolve ( socket ) ;
356- } ) ;
357- socket . on ( 'error' , ( error ) => {
358- reject ( error ) ;
359- } ) ;
360- socket . connect ( port ) ;
361- } ) ;
362- }
363-
364- private registerHandlers ( client : LanguageClient ) {
365- const progressReporting = new ProgressReporting ( client ) ;
366- this . disposables . push ( progressReporting ) ;
367- }
368-
273+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
369274 private withActiveExtention ( ext : vscode . Extension < any > , callback : ( ) => void ) {
370275 if ( ext . isActive ) {
371276 callback ( ) ;
0 commit comments