in runtimes/runtimes/standalone.ts [167:459]
function initializeRuntime(encryptionKey?: string) {
const documents = new TextDocuments(TextDocument)
// Set up telemetry over LSP
const telemetry: Telemetry = {
emitMetric: metric => lspConnection.telemetry.logEvent(metric),
onClientTelemetry: handler => lspConnection.onNotification(telemetryNotificationType.method, handler),
}
// Set up the workspace sync to use the LSP Text Document Sync capability
const workspace: Workspace = {
getTextDocument: async uri => documents.get(uri),
getAllTextDocuments: async () => documents.all(),
// Get all workspace folders and return the workspace folder that contains the uri
getWorkspaceFolder: uri => {
const fileUrl = new URL(uri)
const normalizedFileUri = fileUrl.pathname || ''
const folders = lspRouter.clientInitializeParams!.workspaceFolders
if (!folders) return undefined
for (const folder of folders) {
const folderUrl = new URL(folder.uri)
const normalizedFolderUri = folderUrl.pathname || ''
if (normalizedFileUri.startsWith(normalizedFolderUri)) {
return folder
}
}
},
fs: {
copyFile: (src, dest, options?) => {
if (options?.ensureDir === true) {
const destDir = path.dirname(dest)
if (!existsSync(destDir)) {
mkdirSync(destDir, { recursive: true })
}
}
return copyFile(src, dest)
},
exists: path =>
access(path)
.then(() => true)
.catch(() => false),
getFileSize: path => stat(path),
getServerDataDirPath: serverName => getServerDataDirPath(serverName, lspRouter.clientInitializeParams),
getTempDirPath: () =>
path.join(
// https://github.com/aws/aws-toolkit-vscode/issues/240
os.type() === 'Darwin' ? '/tmp' : os.tmpdir(),
'aws-language-servers'
),
getUserHomeDir: () => os.homedir(),
readdir: path => readdir(path, { withFileTypes: true }),
readFile: (path, options?) =>
readFile(path, { encoding: (options?.encoding || 'utf-8') as BufferEncoding }),
rm: (dir, options?) => rm(dir, options),
isFile: path => stat(path).then(({ isFile }) => isFile()),
writeFile: (path, data, options?) => writeFile(path, data, options),
appendFile: (path, data) => appendFile(path, data),
mkdir: (path, options?) => mkdir(path, options),
readFileSync: (path, options?) =>
readFileSync(path, { encoding: (options?.encoding || 'utf-8') as BufferEncoding }),
},
}
if (!encryptionKey) {
chat = new BaseChat(lspConnection)
}
const identityManagement: IdentityManagement = {
onListProfiles: handler => lspConnection.onRequest(listProfilesRequestType, handler),
onUpdateProfile: handler => lspConnection.onRequest(updateProfileRequestType, handler),
onGetSsoToken: handler =>
lspConnection.onRequest(
getSsoTokenRequestType,
async (params: GetSsoTokenParams, token: CancellationToken) => {
const result = await handler(params, token)
// Encrypt SsoToken.accessToken before sending to client
if (result && !(result instanceof Error) && encryptionKey) {
if (result.ssoToken.accessToken) {
result.ssoToken.accessToken = await encryptObjectWithKey(
result.ssoToken.accessToken,
encryptionKey
)
}
if (result.updateCredentialsParams.data && !result.updateCredentialsParams.encrypted) {
result.updateCredentialsParams.data = await encryptObjectWithKey(
// decodeCredentialsRequestToken expects nested 'data' fields
{ data: result.updateCredentialsParams.data },
encryptionKey
)
result.updateCredentialsParams.encrypted = true
}
}
return result
}
),
onInvalidateSsoToken: handler => lspConnection.onRequest(invalidateSsoTokenRequestType, handler),
sendSsoTokenChanged: params => lspConnection.sendNotification(ssoTokenChangedRequestType, params),
}
const credentialsProvider: CredentialsProvider = auth.getCredentialsProvider()
const runtime: Runtime = {
serverInfo: {
name: props.name,
version: props.version,
},
platform: os.platform(),
// gets the configurations from the environment variables
getConfiguration(key: string) {
return process.env[key]
},
}
const encoding: Encoding = {
encode: value => Buffer.from(value).toString('base64'),
decode: value => Buffer.from(value, 'base64').toString('utf-8'),
}
const loggingServer = new LoggingServer(lspConnection, encoding)
const logging: Logging = loggingServer.getLoggingObject()
lspRouter.servers.push(loggingServer.getLspServer())
const telemetryLspServer = getTelemetryLspServer(lspConnection, encoding, logging, props, runtime)
lspRouter.servers.push(telemetryLspServer)
const sdkProxyConfigManager = new ProxyConfigManager(telemetry)
const agent = newAgent()
// Initialize every Server
const disposables = props.servers.map(s => {
// Create LSP server representation that holds internal server state
// and processes LSP event handlers
const lspServer = new LspServer(lspConnection, encoding, logging)
lspRouter.servers.push(lspServer)
// Set up LSP events handlers per server
// TODO: Move lsp feature inside lspServer
const lsp: Lsp = {
addInitializer: lspServer.setInitializeHandler,
onInitialized: lspServer.setInitializedHandler,
getClientInitializeParams: getClientInitializeParamsHandlerFactory(lspRouter),
onCompletion: handler => lspConnection.onCompletion(handler),
onInlineCompletion: handler => lspConnection.onRequest(inlineCompletionRequestType, handler),
didChangeConfiguration: lspServer.setDidChangeConfigurationHandler,
onDidFormatDocument: handler => lspConnection.onDocumentFormatting(handler),
onDidOpenTextDocument: handler => documentsObserver.callbacks.onDidOpenTextDocument(handler),
onDidChangeTextDocument: handler => documentsObserver.callbacks.onDidChangeTextDocument(handler),
onDidCloseTextDocument: handler => documentsObserver.callbacks.onDidCloseTextDocument(handler),
onDidSaveTextDocument: handler => documentsObserver.callbacks.onDidSaveTextDocument(handler),
onExecuteCommand: lspServer.setExecuteCommandHandler,
onSemanticTokens: handler => lspConnection.onRequest(SemanticTokensRequest.type, handler),
workspace: {
applyWorkspaceEdit: params => lspConnection.workspace.applyEdit(params),
getConfiguration: section => lspConnection.workspace.getConfiguration(section),
onDidChangeWorkspaceFolders: handler =>
lspConnection.onNotification(DidChangeWorkspaceFoldersNotification.method, handler),
onDidCreateFiles: params => lspConnection.workspace.onDidCreateFiles(params),
onDidDeleteFiles: params => lspConnection.workspace.onDidDeleteFiles(params),
onDidRenameFiles: params => lspConnection.workspace.onDidRenameFiles(params),
onUpdateConfiguration: lspServer.setUpdateConfigurationHandler,
selectWorkspaceItem: params =>
lspConnection.sendRequest(selectWorkspaceItemRequestType.method, params),
openFileDiff: params => lspConnection.sendNotification(openFileDiffNotificationType.method, params),
},
window: {
showMessage: params => lspConnection.sendNotification(ShowMessageNotification.method, params),
showMessageRequest: params => lspConnection.sendRequest(ShowMessageRequest.method, params),
showDocument: params => lspConnection.sendRequest(ShowDocumentRequest.method, params),
showSaveFileDialog: (params: ShowSaveFileDialogParams) =>
lspConnection.sendRequest(ShowSaveFileDialogRequestType.method, params),
},
publishDiagnostics: params =>
lspConnection.sendNotification(PublishDiagnosticsNotification.method, params),
sendProgress: async <P>(type: ProgressType<P>, token: ProgressToken, value: P) => {
if (encryptionKey) {
const encryptedProgress = await encryptObjectWithKey(value as Object, encryptionKey)
return lspConnection.sendProgress(type, token, encryptedProgress as P)
}
return lspConnection.sendProgress(type, token, value)
},
onHover: handler => lspConnection.onHover(handler),
onSignatureHelp: handler => lspConnection.onSignatureHelp(handler),
extensions: {
onGetConfigurationFromServer: lspServer.setServerConfigurationHandler,
onInlineCompletionWithReferences: handler =>
lspConnection.onRequest(inlineCompletionWithReferencesRequestType, handler),
onLogInlineCompletionSessionResults: handler => {
lspConnection.onNotification(logInlineCompletionSessionResultsNotificationType, handler)
},
onDidChangeDependencyPaths(handler) {
lspConnection.onNotification(didChangeDependencyPathsNotificationType, handler)
},
},
}
const isExperimentalProxy = process.env.EXPERIMENTAL_HTTP_PROXY_SUPPORT === 'true'
const sdkInitializator: SDKInitializator = Object.assign(
// Default v3 implementation as the callable function
<T, P>(Ctor: SDKClientConstructorV3<T, P>, current_config: P): T => {
try {
const requestHandler = isExperimentalProxy
? sdkProxyConfigManager.getV3ProxyConfig()
: makeProxyConfigv3Standalone(workspace)
logging.log(`Using ${isExperimentalProxy ? 'experimental' : 'standard'} proxy util`)
// setup proxy
let instance = new Ctor({
...current_config,
requestHandler: requestHandler,
})
logging.log(`Configured AWS SDK V3 Proxy for client.`)
return instance
} catch (err) {
telemetry.emitMetric({
name: 'runtime_httpProxyConfiguration',
result: 'Failed',
errorData: {
reason: err instanceof Error ? err.toString() : 'unknown',
},
})
// Fallback
logging.log(`Failed to configure AWS SDK V3 Proxy for client. Starting without proxy.`)
return new Ctor({ ...current_config })
}
},
// v2 implementation as a property
{
v2: <T extends Service, P extends ServiceConfigurationOptions>(
Ctor: SDKClientConstructorV2<T, P>,
current_config: P
): T => {
let instance = new Ctor({ ...current_config })
try {
const configOptions = isExperimentalProxy
? sdkProxyConfigManager.getV2ProxyConfig()
: makeProxyConfigv2Standalone(workspace)
logging.log(`Using ${isExperimentalProxy ? 'experimental' : 'standard'} proxy util`)
instance.config.update(configOptions)
logging.log(`Configured AWS SDK V2 Proxy for client.`)
return instance
} catch (err) {
telemetry.emitMetric({
name: 'runtime_httpProxyConfiguration',
result: 'Failed',
errorData: {
reason: err instanceof Error ? err.toString() : 'unknown',
},
})
// Fallback
logging.log(`Failed to configure AWS SDK V2 Proxy for client. Starting without proxy.`)
return instance
}
},
}
)
credentialsProvider.onCredentialsDeleted = lspServer.setCredentialsDeleteHandler
return s({
chat,
credentialsProvider,
lsp,
workspace,
telemetry,
logging,
runtime,
identityManagement,
notification: lspServer.notification,
sdkInitializator: sdkInitializator,
agent,
})
})
// Free up any resources or threads used by Servers
lspConnection.onExit(() => {
disposables.forEach(d => d())
})
// Initialize the documents listener and start the LSP connection
documents.listen(documentsObserver.callbacks)
lspConnection.listen()
}