From eb6ec2193cd406b3284ae72e54c866bf99b3627b Mon Sep 17 00:00:00 2001 From: Brett Saviano Date: Wed, 26 Aug 2026 08:26:02 -0400 Subject: [PATCH 1/2] Activate faster when there are many workspace servers --- client/src/extension.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client/src/extension.ts b/client/src/extension.ts index 38e91b0..f198975 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -167,6 +167,10 @@ export async function activate(context: ExtensionContext) { async function resolveServerSpec(uri: Uri): Promise { try { const wsFolderUriString = workspace.getWorkspaceFolder(uri)?.uri.toString(); + if (wsFolderUriString && wsFolderServerSpecs.has(wsFolderUriString)) { + // Return the cached server spec if we have it + return wsFolderServerSpecs.get(wsFolderUriString)!; + } const serverSpec = objectScriptApi.serverForUri(uri)!; const auth = serverSpec.auth ?? new BasicAuthorization(serverSpec.username, serverSpec.password); if ( @@ -246,11 +250,12 @@ export async function activate(context: ExtensionContext) { } } - // Ensure that every server has at most one session. + // Ensure that every server has at most one session for (const f of workspace.workspaceFolders ?? []) { try { const serverSpec = await resolveServerSpec(f.uri); - if (serverSpec?.active) { + if (serverSpec?.active && !getCookies(serverSpec).length) { + // Skip inactive servers and those that we already have cookies for await makeRESTRequest("HEAD", 0, "", serverSpec); } } catch { From 62400ee9eb409004c1e9c6c33813d422a33be2f2 Mon Sep 17 00:00:00 2001 From: Brett Saviano Date: Mon, 31 Aug 2026 11:55:17 -0400 Subject: [PATCH 2/2] Update extension.ts --- client/src/extension.ts | 88 +++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/client/src/extension.ts b/client/src/extension.ts index 87f28dc..7d21850 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -50,7 +50,7 @@ export let client: { const cookiesCache: Map = new Map(); export function updateCookies(newCookies: string[], server: ServerSpec): string[] { - const key = `${server.username}@${server.host}:${server.port}${server.pathPrefix}`; + const key = `${server.username}@${server.host}:${server.port}${server.pathPrefix}`.toLowerCase(); const cookies = cookiesCache.get(key) ?? []; newCookies.forEach((cookie) => { const [cookieName] = cookie.split("="); @@ -66,14 +66,14 @@ export function updateCookies(newCookies: string[], server: ServerSpec): string[ } export function getCookies(server: ServerSpec): string[] { - return cookiesCache.get(`${server.username}@${server.host}:${server.port}${server.pathPrefix}`) ?? []; + return cookiesCache.get(`${server.username}@${server.host}:${server.port}${server.pathPrefix}`.toLowerCase()) ?? []; } let objectScriptApi: serverManager.VSCodeObjectScriptAPI; let serverManagerApi: serverManager.ServerManagerAPI; -/** Resolved connection information for each workspace folder */ -const wsFolderServerSpecs: Map = new Map(); +/** Resolved connection information */ +const resolvedServerSpecs: Map = new Map(); export async function activate(context: ExtensionContext) { // Get the main extension exported API @@ -147,7 +147,7 @@ export async function activate(context: ExtensionContext) { // Send custom notifications when the connection or password changes objectScriptApi.onDidChangeConnection()(() => { - wsFolderServerSpecs.clear(); + resolvedServerSpecs.clear(); client.sendNotification("intersystems/server/connectionChange"); }); const serverManagerExt = extensions.getExtension("intersystems-community.servermanager"); @@ -155,8 +155,8 @@ export async function activate(context: ExtensionContext) { // The server manager extension is installed serverManagerApi = serverManagerExt.isActive ? serverManagerExt.exports : await serverManagerExt.activate(); serverManagerApi.onDidChangePassword()((serverName: string) => { - for (const [k, v] of wsFolderServerSpecs.entries()) { - if (v.serverName == serverName) wsFolderServerSpecs.delete(k); + for (const [k, v] of resolvedServerSpecs.entries()) { + if (v.serverName == serverName) resolvedServerSpecs.delete(k); } client.sendNotification("intersystems/server/passwordChange", serverName); }); @@ -166,14 +166,25 @@ export async function activate(context: ExtensionContext) { // for a missing password via the Server Manager's authentication provider. async function resolveServerSpec(uri: Uri): Promise { try { - const wsFolderUriString = workspace.getWorkspaceFolder(uri)?.uri.toString(); - if (wsFolderUriString && wsFolderServerSpecs.has(wsFolderUriString)) { - // Return the cached server spec if we have it - return wsFolderServerSpecs.get(wsFolderUriString)!; - } const serverSpec = objectScriptApi.serverForUri(uri); - if (serverSpec === undefined) return; + if (!serverSpec?.active) { + // An inactive connection is indistinguishable from no connection at all + return; + } const auth = serverSpec.auth ?? new BasicAuthorization(serverSpec.username, serverSpec.password); + if ([undefined, ""].includes(auth?.username)) { + const partialKey = `${serverSpec.host}:${serverSpec.port}${serverSpec.pathPrefix}`.toLowerCase(); + for (const key of resolvedServerSpecs.keys()) { + // The username isn't known yet, so see if we have a connection to this server that is already known + if (key.toLowerCase().slice(key.indexOf("@") + 1) == partialKey) { + return resolvedServerSpecs.get(key); + } + } + } else { + // Return resolved spec if we have one that matches exactly + const key = `${auth.username}@${serverSpec.host}:${serverSpec.port}${serverSpec.pathPrefix}`.toLowerCase(); + if (resolvedServerSpecs.has(key)) return resolvedServerSpecs.get(key); + } if ( // Server was resolved serverSpec.host !== "" && @@ -230,28 +241,29 @@ export async function activate(context: ExtensionContext) { username: auth.username, credentials: auth.credentials, }; - if (wsFolderUriString && !wsFolderServerSpecs.has(wsFolderUriString)) { - wsFolderServerSpecs.set(wsFolderUriString, server); - } + const serverKey = `${server.username}@${server.host}:${server.port}${server.pathPrefix}`.toLowerCase(); + if (!resolvedServerSpecs.has(serverKey)) resolvedServerSpecs.set(serverKey, server); return server; } catch { // Treat any thrown error as "no server connection" } } - // Ensure that every server has at most one session + // Resolve the server connection for every workspace folder for (const f of workspace.workspaceFolders ?? []) { try { - const serverSpec = await resolveServerSpec(f.uri); - if (serverSpec?.active && !getCookies(serverSpec).length) { - // Skip inactive servers and those that we already have cookies for - await makeRESTRequest("HEAD", 0, "", serverSpec); - } + await resolveServerSpec(f.uri); } catch { - // Ignore any failure; the session will be created on demand instead + // Ignore any failure; the server will be resolved on demand instead } } + // Create a CSP session for all resolved server connections + // Ignore any failures; the sessions will be created on demand instead + const headPromises: Promise[] = []; + resolvedServerSpecs.forEach((server) => headPromises.push(makeRESTRequest("HEAD", 0, "", server))); + await Promise.allSettled(headPromises); + const textDecoder = new TextDecoder(); context.subscriptions.push( // Register custom request handlers @@ -434,27 +446,17 @@ export async function activate(context: ExtensionContext) { export async function deactivate(): Promise { // Stop the server and log out of all CSP sessions - const loggedOut: Set = new Set(); const promises: Promise[] = client ? [client.stop()] : []; - for (const f of workspace.workspaceFolders ?? []) { - const serverSpec = wsFolderServerSpecs.get(f.uri.toString()); - if (!serverSpec?.active) continue; - const sessionCookie = getCookies(serverSpec).find((c) => c.startsWith("CSPSESSIONID-")); - if (!sessionCookie || loggedOut.has(sessionCookie)) continue; - loggedOut.add(sessionCookie); - promises.push( - makeRESTRequest( - "HEAD", - 0, - "", - serverSpec, - undefined, - undefined, - // Prefer IRISLogout for servers that support it - lt(serverSpec.serverVersion, "2018.2.0") ? { CacheLogout: "end" } : { IRISLogout: "end" }, - ), - ); - } + resolvedServerSpecs.forEach((server) => promises.push(makeRESTRequest( + "HEAD", + 0, + "", + server, + undefined, + undefined, + // Prefer IRISLogout for servers that support it + lt(server.serverVersion, "2018.2.0") ? { CacheLogout: "end" } : { IRISLogout: "end" }, + ))); await Promise.allSettled(promises); }