Skip to content
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

Open path from URI #2038

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
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
12 changes: 10 additions & 2 deletions src/api/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,17 @@ export interface StoredConnection {
const getPasswordKey = (connectionName:string) => `${connectionName}_password`;

export namespace ConnectionManager {
export function getByName(name: string): StoredConnection | undefined {
export function getByHost(host: string, caseInsensitive = false): StoredConnection | undefined {
const connections = getAll();
const index = connections.findIndex(conn => conn.name === name);
const index = connections.findIndex(conn => caseInsensitive ? conn.host.toLowerCase() === host.toLowerCase() : conn.host === host);
if (index !== -1) {
return { index, data: connections[index] };
}
}

export function getByName(name: string, caseInsensitive = false): StoredConnection | undefined {
const connections = getAll();
const index = connections.findIndex(conn => caseInsensitive ? conn.name.toLowerCase() === name.toLowerCase() : conn.name === name);
if (index !== -1) {
return { index, data: connections[index] };
}
Expand Down
7 changes: 4 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { Deployment } from "./api/local/deployment";
import { IFSFS } from "./filesystems/ifsFs";
import { LocalActionCompletionItemProvider } from "./languages/actions/completion";
import { updateLocale } from "./locale";
import * as Sandbox from "./sandbox";
import { initialise } from "./testing";
import { CodeForIBMi, ConnectionData } from "./typings";
import { initializeConnectionBrowser } from "./views/ConnectionBrowser";
Expand All @@ -31,6 +30,8 @@ import { initializeIFSBrowser } from "./views/ifsBrowser";
import { initializeObjectBrowser } from "./views/objectBrowser";
import { initializeSearchView } from "./views/searchView";
import { SettingsUI } from "./webviews/settings";
import { registerUriHandler } from "./uri";
import { handleSandboxStartup } from "./sandbox";

export async function activate(context: ExtensionContext): Promise<CodeForIBMi> {
// Use the console to output diagnostic information (console.log) and errors (console.error)
Expand Down Expand Up @@ -105,8 +106,8 @@ export async function activate(context: ExtensionContext): Promise<CodeForIBMi>
Deployment.initialize(context);
updateLastConnectionAndServerCache();

Sandbox.handleStartup();
Sandbox.registerUriHandler(context);
handleSandboxStartup();
registerUriHandler(context);

console.log(`Developer environment: ${process.env.DEV}`);
if (process.env.DEV) {
Expand Down
4 changes: 4 additions & 0 deletions src/locale/ids/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,10 @@
"searchView.find.message": "{0} file(s) named '{1}'",
"searchView.search.message": "{0} file(s) contain(s) '{1}'",
"service.certificate.exists": "Remote service certificate exists",
"uriOpen.openError": "Error opening file",
"uriOpen.hostMismatch": "A file on another host is trying to be opened. Do you want to open on the current connection instead?",
"uriOpen.missingPath": "The provided URI is missing the path attribute.",
"uriOpen.noConnection": "You must have an active connection to open a file.",
"shortcut": "shortcut",
"size": "Size",
"skip": "Skip",
Expand Down
95 changes: 3 additions & 92 deletions src/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,96 +7,7 @@ import { instance } from "./instantiate";
import { t } from "./locale";
import { ConnectionData } from "./typings";

export async function registerUriHandler(context: ExtensionContext) {
context.subscriptions.push(
window.registerUriHandler({
async handleUri(uri: Uri) {
console.log(uri);

const connection = instance.getConnection();

switch (uri.path) {
case `/connect`:
if (connection === undefined) {
const queryData = querystring.parse(uri.query);

const save = queryData.save === `true`;
const server = String(queryData.server);
let user: string | string[] | undefined = queryData.user;
let pass: string | string[] | undefined = queryData.pass;

if (server) {
if (!user) {
user = await window.showInputBox({
title: t(`sandbox.input.user.title`),
prompt: t(`sandbox.input.user.prompt`, server)
});
}

if (pass) {
pass = Buffer.from(String(pass), `base64`).toString();
} else {
pass = await window.showInputBox({
password: true,
title: t(`sandbox.input.password.title`),
prompt: t(`sandbox.input.password.prompt`, String(user), server)
});
}

if (user && pass) {
const serverParts = String(server).split(`:`);
const host = serverParts[0];
const port = serverParts.length === 2 ? Number(serverParts[1]) : 22;

const connectionData: ConnectionData = {
host,
name: `${user}-${host}`,
username: String(user),
password: String(pass),
port
};

const connectionResult = await commands.executeCommand(`code-for-ibmi.connectDirect`, connectionData);

if (connectionResult) {
await initialSetup(connectionData.username);

if (save) {
const existingConnection = ConnectionManager.getByName(connectionData.name);

if (!existingConnection) {
// New connection!
await ConnectionManager.storeNew(connectionData);
}
}

} else {
window.showInformationMessage(t(`sandbox.failedToConnect.title`), {
modal: true,
detail: t(`sandbox.failedToConnect`, server, user)
});
}

} else {
window.showErrorMessage(t(`sandbox.noPassword`, server));
}
}
} else {
window.showInformationMessage(t(`sandbox.failedToConnect.title`), {
modal: true,
detail: t(`sandbox.alreadyConnected`)
});
}

break;
}

}
})
);
}

export async function handleStartup() {
export async function handleSandboxStartup() {

let server: string | undefined = env.SANDBOX_SERVER;
let username: string | undefined = env.SANDBOX_USER;
Expand Down Expand Up @@ -156,7 +67,7 @@ export async function handleStartup() {
const connectionResult = await commands.executeCommand(`code-for-ibmi.connectDirect`, connectionData);

if (connectionResult) {
await initialSetup(connectionData.username);
await initialSandboxSetup(connectionData.username);

} else {
window.showInformationMessage(t(`sandbox.noconnection.modal.title`), {
Expand All @@ -167,7 +78,7 @@ export async function handleStartup() {
}
}

async function initialSetup(username: string) {
export async function initialSandboxSetup(username: string) {
const config = instance.getConfig();
if (config) {
const libraryList = config.libraryList;
Expand Down
153 changes: 153 additions & 0 deletions src/uri/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import querystring from "querystring";
import { commands, ExtensionContext, Uri, window } from "vscode";
import { ConnectionManager, GlobalConfiguration } from "../api/Configuration";
import { instance } from "../instantiate";
import { t } from "../locale";
import { ConnectionData } from "../typings";
import { initialSandboxSetup } from "../sandbox";

export async function registerUriHandler(context: ExtensionContext) {
context.subscriptions.push(
window.registerUriHandler({
async handleUri(uri: Uri) {
const queryData = querystring.parse(uri.query);

const connection = instance.getConnection();

switch (uri.path) {
case '/open':
if (queryData.path) {
if (queryData.host) {
const host = Array.isArray(queryData.host) ? queryData.host[0] : queryData.host;
if (connection) {
if (host !== connection.currentHost) {
const chosen = await window.showInformationMessage(t(`uriOpen.openError`), {
detail: t(`uriOpen.hostMismatch`),
modal: true
}, `Open`);

if (chosen !== `Open`) {
return;
}
}
} else {
const connection = ConnectionManager.getByHost(host, true) || ConnectionManager.getByName(host, true);
if (connection) {
let password = await ConnectionManager.getStoredPassword(context, connection.data.name);

if (!password) {
password = await window.showInputBox({
password: true,
title: t(`sandbox.input.password.title`),
prompt: t(`sandbox.input.password.prompt`, connection.data.username, connection.data.host)
});
}

const connected = await commands.executeCommand(`code-for-ibmi.connectDirect`, {
...connection.data,
password
});

if (!connected) {
window.showWarningMessage(t(`uriOpen.noConnection`));
return;
};
} else {
window.showWarningMessage(t(`uriOpen.noConnection`));
return;
}
}

const paths = Array.isArray(queryData.path) ? queryData.path : [queryData.path];
for (const path of paths) {
commands.executeCommand(`code-for-ibmi.openEditable`, path);
}
} else {
window.showWarningMessage(t(`uriOpen.missingPath`));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the example you gave in this PR:

vscode://halcyontechltd.code-for-ibmi/open?path=/home/liama/xyz

I assume this means that the file will be opened based on the active connection. If so, is this else block a mistake because this will not open any file and just give this warning even though I am connected. In the case there is no connection, shouldn't the message be:

window.showWarningMessage(t(`uriOpen.noConnection`));

}
} else {
window.showWarningMessage(t(`uriOpen.noConnection`));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
window.showWarningMessage(t(`uriOpen.noConnection`));
window.showWarningMessage(t(`uriOpen.missingPath`));

}
break;

case `/connect`:
if (connection === undefined) {
const save = queryData.save === `true`;
const server = String(queryData.server);
let user: string | string[] | undefined = queryData.user;
let pass: string | string[] | undefined = queryData.pass;

if (server) {
if (!user) {
user = await window.showInputBox({
title: t(`sandbox.input.user.title`),
prompt: t(`sandbox.input.user.prompt`, server)
});
}

if (pass) {
pass = Buffer.from(String(pass), `base64`).toString();
} else {
pass = await window.showInputBox({
password: true,
title: t(`sandbox.input.password.title`),
prompt: t(`sandbox.input.password.prompt`, String(user), server)
});
}

if (user && pass) {
const serverParts = String(server).split(`:`);
const host = serverParts[0];
const port = serverParts.length === 2 ? Number(serverParts[1]) : 22;

const connectionData: ConnectionData = {
host,
name: `${user}-${host}`,
username: String(user),
password: String(pass),
port
};

const connectionResult = await commands.executeCommand(`code-for-ibmi.connectDirect`, connectionData);

if (connectionResult) {
await initialSandboxSetup(connectionData.username);

if (save) {
const existingConnection = ConnectionManager.getByHost(host);

if (!existingConnection) {
await ConnectionManager.storeNew({
...connectionData,
password: undefined, // Removes the password from the object
});

await ConnectionManager.setStoredPassword(context, host, pass);
}
}

} else {
window.showInformationMessage(t(`sandbox.failedToConnect.title`), {
modal: true,
detail: t(`sandbox.failedToConnect`, server, user)
});
}

} else {
window.showErrorMessage(t(`sandbox.noPassword`, server));
}
}
} else {
window.showInformationMessage(t(`sandbox.failedToConnect.title`), {
modal: true,
detail: t(`sandbox.alreadyConnected`)
});
}

break;
}

}
})
);
}
Loading