Skip to content

Extend objectscript.conn.docker-compose settings object to handle superserver port identification #1485

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1289,7 +1289,11 @@
"type": "string"
},
"internalPort": {
"description": "Target port inside the service in docker-compose.",
"description": "Target webserver port inside the service in docker-compose.",
"type": "number"
},
"internalSuperserverPort": {
"description": "Target superserver port inside the service in docker-compose.",
"type": "number"
},
"file": {
Expand Down
9 changes: 9 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ interface ConnectionSettings {
https: boolean;
host: string;
port: number;
superserverPort?: number;
pathPrefix: string;
ns: string;
username: string;
Expand Down Expand Up @@ -67,6 +68,9 @@ export class AtelierAPI {
const wsKey = this.configName.toLowerCase();
const host = this.externalServer ? this._config.host : workspaceState.get(wsKey + ":host", this._config.host);
const port = this.externalServer ? this._config.port : workspaceState.get(wsKey + ":port", this._config.port);
const superserverPort = this.externalServer
? this._config.superserverPort
: workspaceState.get(wsKey + ":superserverPort", this._config.superserverPort);
const password = workspaceState.get(wsKey + ":password", this._config.password);
const apiVersion = workspaceState.get(wsKey + ":apiVersion", DEFAULT_API_VERSION);
const serverVersion = workspaceState.get(wsKey + ":serverVersion", DEFAULT_SERVER_VERSION);
Expand All @@ -80,6 +84,7 @@ export class AtelierAPI {
https,
host,
port,
superserverPort,
pathPrefix,
ns,
username,
Expand Down Expand Up @@ -211,6 +216,7 @@ export class AtelierAPI {
webServer: { scheme, host, port, pathPrefix = "" },
username,
password,
superServer,
} = getResolvedConnectionSpec(serverName, config("intersystems.servers", workspaceFolderName).get(serverName));
this._config = {
serverName,
Expand All @@ -221,6 +227,7 @@ export class AtelierAPI {
ns,
host,
port,
superserverPort: superServer.port,
username,
password,
pathPrefix,
Expand All @@ -241,6 +248,7 @@ export class AtelierAPI {
webServer: { scheme, host, port, pathPrefix = "" },
username,
password,
superServer,
} = resolvedSpec;
this._config = {
serverName: "",
Expand All @@ -251,6 +259,7 @@ export class AtelierAPI {
ns,
host,
port,
superserverPort: superServer.port,
username,
password,
pathPrefix,
Expand Down
29 changes: 24 additions & 5 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ export async function resolveConnectionSpec(serverName: string, uri?: vscode.Uri
port: serverForUri.port,
pathPrefix: serverForUri.pathPrefix,
},
superServer: {
port: serverForUri.superserverPort,
},
username: serverForUri.username,
password: serverForUri.password ? serverForUri.password : undefined,
description: `Server for workspace folder '${serverName}'`,
Expand Down Expand Up @@ -330,14 +333,15 @@ export async function checkConnection(
/// clean-up cached values
await workspaceState.update(wsKey + ":host", undefined);
await workspaceState.update(wsKey + ":port", undefined);
await workspaceState.update(wsKey + ":superserverPort", undefined);
await workspaceState.update(wsKey + ":password", undefined);
await workspaceState.update(wsKey + ":apiVersion", undefined);
await workspaceState.update(wsKey + ":serverVersion", undefined);
await workspaceState.update(wsKey + ":docker", undefined);
_onDidChangeConnection.fire();
}
let api = new AtelierAPI(apiTarget, false);
const { active, host = "", port = 0, username, ns = "" } = api.config;
const { active, host = "", port = 0, superserverPort = 0, username, ns = "" } = api.config;
vscode.commands.executeCommand("setContext", "vscode-objectscript.connectActive", active);
if (!panel.text) {
panel.text = `${PANEL_LABEL}`;
Expand All @@ -360,11 +364,16 @@ export async function checkConnection(

if (!workspaceState.get(wsKey + ":port") && !api.externalServer) {
try {
const { port: dockerPort, docker: withDocker, service } = await portFromDockerCompose();
const {
port: dockerPort,
superserverPort: dockerSuperserverPort,
docker: withDocker,
service,
} = await portFromDockerCompose(configName);
workspaceState.update(wsKey + ":docker", withDocker);
workspaceState.update(wsKey + ":dockerService", service);
if (withDocker) {
if (!dockerPort) {
if (!dockerPort || !dockerSuperserverPort) {
const errorMessage = `Something is wrong with your docker-compose connection settings, or your service is not running.`;
handleError(errorMessage);
panel.text = `${PANEL_LABEL} $(error)`;
Expand All @@ -377,6 +386,9 @@ export async function checkConnection(
workspaceState.update(wsKey + ":host", "localhost");
workspaceState.update(wsKey + ":port", dockerPort);
}
if (dockerSuperserverPort !== superserverPort) {
workspaceState.update(wsKey + ":superserverPort", dockerSuperserverPort);
}
connInfo = `localhost:${dockerPort}[${ns}]`;
_onDidChangeConnection.fire();
}
Expand Down Expand Up @@ -1627,6 +1639,7 @@ function serverForUri(uri: vscode.Uri): any {
host = "",
https,
port,
superserverPort,
pathPrefix,
username,
password,
Expand All @@ -1640,6 +1653,7 @@ function serverForUri(uri: vscode.Uri): any {
scheme: https ? "https" : "http",
host,
port,
superserverPort,
pathPrefix,
username,
password:
Expand All @@ -1661,9 +1675,14 @@ async function asyncServerForUri(uri: vscode.Uri): Promise<any> {
if (apiTarget instanceof vscode.Uri) {
apiTarget = vscode.workspace.getWorkspaceFolder(apiTarget)?.name;
}
const { port: dockerPort, docker: withDocker } = await portFromDockerCompose(apiTarget);
if (withDocker && dockerPort) {
const {
port: dockerPort,
superserverPort: dockerSuperserverPort,
docker: withDocker,
} = await portFromDockerCompose(apiTarget);
if (withDocker && dockerPort && dockerSuperserverPort) {
server.port = dockerPort;
server.superserverPort = dockerSuperserverPort;
server.host = "localhost";
server.pathPrefix = "";
server.https = false;
Expand Down
42 changes: 31 additions & 11 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,24 +490,30 @@ async function composeCommand(cwd?: string): Promise<string> {

export async function portFromDockerCompose(
workspaceFolderName?: string
): Promise<{ port: number; docker: boolean; service?: string }> {
): Promise<{ port: number; superserverPort: number; docker: boolean; service?: string }> {
// When running remotely, behave as if there is no docker-compose object within objectscript.conn
if (extensionContext.extension.extensionKind === vscode.ExtensionKind.Workspace) {
return { docker: false, port: null };
return { docker: false, port: null, superserverPort: null };
}

// Seek a valid docker-compose object within objectscript.conn
const { "docker-compose": dockerCompose = {} } = config("conn", workspaceFolderName);
const { service, file = "docker-compose.yml", internalPort = 52773, envFile } = dockerCompose;
if (!internalPort || !file || !service || service === "") {
return { docker: false, port: null };
}

const result = { port: null, docker: true, service };
const {
service,
file = "docker-compose.yml",
internalPort = 52773,
internalSuperserverPort = 1972,
envFile,
} = dockerCompose;
if (!internalPort || !internalSuperserverPort || !file || !service || service === "") {
return { docker: false, port: null, superserverPort: null };
}

const result = { port: null, superserverPort: null, docker: true, service };
const workspaceFolder = uriOfWorkspaceFolder(workspaceFolderName);
if (!workspaceFolder) {
// No workspace folders are open
return { docker: false, port: null };
return { docker: false, port: null, superserverPort: null };
}
const workspaceFolderPath = workspaceFolder.fsPath;
const workspaceRootPath = vscode.workspace.workspaceFolders[0].uri.fsPath;
Expand Down Expand Up @@ -548,9 +554,23 @@ export async function portFromDockerCompose(
}
const [, port] = stdout.match(/:(\d+)/) || [];
if (!port) {
reject(`Port ${internalPort} not published for service '${service}' in '${path.join(cwd, file)}'.`);
reject(`Webserver port ${internalPort} not published for service '${service}' in '${path.join(cwd, file)}'.`);
}
resolve({ port: parseInt(port, 10), docker: true, service });
result.port = parseInt(port, 10);

exec(`${cmd} port --protocol=tcp ${service} ${internalSuperserverPort}`, { cwd }, (error, stdout) => {
if (error) {
reject(error.message);
}
const [, superserverPort] = stdout.match(/:(\d+)/) || [];
if (!superserverPort) {
reject(
`Superserver port ${internalSuperserverPort} not published for service '${service}' in '${path.join(cwd, file)}'.`
);
}
result.superserverPort = parseInt(superserverPort, 10);
resolve(result);
});
});
});
});
Expand Down