From a8d5f4acb851444efefb89330b8ac39f58d594e8 Mon Sep 17 00:00:00 2001 From: Levi Yan Date: Thu, 22 May 2025 18:13:17 +0800 Subject: [PATCH] feat: show SSH:project name in status bar --- src/home.ts | 2 +- src/main.ts | 10 ++++--- src/remote-container.ts | 64 ++++++++++++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/home.ts b/src/home.ts index b704eed..caa9d40 100644 --- a/src/home.ts +++ b/src/home.ts @@ -69,7 +69,7 @@ export default class DSHome { break; } case 'firstOpenRemoteFolder': - await this.remoteContainer.firstOpenProject(data.host, data.port, data.username, data.path, this.context) + await this.remoteContainer.firstOpenProject(data.host, data.hostname, data.port, data.username, data.path, this.context) break; case 'openRemoteFolder': this.remoteContainer.openRemoteFolder(data.host, data.port, data.username, data.path); diff --git a/src/main.ts b/src/main.ts index e8bf6dc..71e0120 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,14 +26,16 @@ export class DevStarExtension { if (uri.path === '/openProject') { const params = new URLSearchParams(uri.query); const host = params.get('host'); + const hostname = params.get('hostname'); const port = params.get('port'); const username = params.get('username'); const path = params.get('path'); const access_token = params.get('access_token'); const devstar_username = params.get('devstar_username'); - if (host && port && username && path) { + if (host && hostname && port && username && path) { const container_host = host; + const container_hostname = hostname const container_port = parseInt(port, 10); const container_username = username; const project_path = decodeURIComponent(path); @@ -43,12 +45,12 @@ export class DevStarExtension { // 如果没有用户登录,则直接登录; const res = await this.user.login(access_token, devstar_username) if (res === 'ok') { - await this.remoteContainer.firstOpenProject(container_host, container_port, container_username, project_path, this.context) + await this.remoteContainer.firstOpenProject(container_host, container_hostname, container_port, container_username, project_path, this.context) } } else if (devstar_username === this.user.getUsernameFromLocal()) { // 如果同用户已经登录,则忽略; // 直接打开项目 - await this.remoteContainer.firstOpenProject(container_host, container_port, container_username, project_path, this.context) + await this.remoteContainer.firstOpenProject(container_host, container_hostname,container_port, container_username, project_path, this.context) } else { // 如果不是同用户,可以选择切换用户,或者不切换登录用户,直接打开容器 const selection = await vscode.window.showWarningMessage(`已登录用户:${this.user.getUsernameFromLocal()},是否切换用户?`, @@ -57,7 +59,7 @@ export class DevStarExtension { // 如果没有用户登录,则直接登录; const res = await this.user.login(access_token, devstar_username) if (res === 'ok') { - await this.remoteContainer.firstOpenProject(container_host, container_port, container_username, project_path, this.context) + await this.remoteContainer.firstOpenProject(container_host, container_hostname, container_port, container_username, project_path, this.context) } } else if (selection === 'No') { await openProjectWithoutLogging(container_host, container_port, container_username, project_path); diff --git a/src/remote-container.ts b/src/remote-container.ts index f93af49..964797e 100644 --- a/src/remote-container.ts +++ b/src/remote-container.ts @@ -16,18 +16,36 @@ export default class RemoteContainer { this.user = user } - async firstOpenProject(hostname: string, port: number, username: string, path: string, context: vscode.ExtensionContext) { - await this.firstConnect(hostname, username, port, context) + /** + * 第一次打开远程项目 + * @param host 项目名称 + * @param hostname ip + * @param port + * @param username + * @param path + * @param context 用于支持远程项目环境 + */ + async firstOpenProject(host: string, hostname: string, port: number, username: string, path: string, context: vscode.ExtensionContext) { + await this.firstConnect(host, hostname, username, port, context) .then((res) => { if (res === 'success') { // only success then open folder - this.openRemoteFolder(hostname, port, username, path); + this.openRemoteFolder(host, port, username, path); } }) } + /** + * 本地/远程项目环境下,第一次连接其他项目 + * @param host 项目名称 + * @param hostname ip + * @param username + * @param port + * @param context 用于支持远程项目环境 + * @returns 成功返回success + */ // connect with key - async firstConnect(hostname: string, username: string, port: number, context: vscode.ExtensionContext): Promise { + async firstConnect(host: string, hostname: string, username: string, port: number, context: vscode.ExtensionContext): Promise { return new Promise(async (resolve) => { const ssh = new NodeSSH(); vscode.window.withProgress({ @@ -87,11 +105,10 @@ export default class RemoteContainer { await ssh.dispose(); // ssh信息存储到ssh config file中 - // 远程环境,利用global state中记录的localSystemName来决定执行的命令 + // 远程项目环境,利用global state中记录的localSystemName来决定执行的命令 const localSystemName = utils.getLocalSystemName(context) const localSSHConfigPath = utils.getLocalSSHConfigPath(context); const privateKeyPath = this.user.getLocalUserPrivateKeyPath(); - const host = `${hostname}-${port}` // host: hostname-port const newSShConfigContent = `\nHost ${host}\n HostName ${hostname}\n Port ${port}\n User ${username}\n PreferredAuthentications publickey\n IdentityFile ${privateKeyPath}\n `; let commandToAppend: string; @@ -164,7 +181,7 @@ export default class RemoteContainer { await ssh.dispose(); // only connect successfully then save the host info - await this.storeHostInfo(hostname, port, username) + await this.storeProjectSSHInfo(host, hostname, port, username) resolve('success') } catch (error) { @@ -176,7 +193,14 @@ export default class RemoteContainer { }); } - async storeHostInfo(hostname: string, port: number, username: string): Promise { + /** + * 本地环境,保存项目的ssh连接信息 + * @param host + * @param hostname + * @param port + * @param username + */ + async storeProjectSSHInfo(host: string, hostname: string, port: number, username: string): Promise { const sshConfigPath = path.join(os.homedir(), '.ssh', 'config'); // check if the host and related info exist in local ssh config file before saving var canAppendSSHConfig = true @@ -184,8 +208,7 @@ export default class RemoteContainer { var reader = rd.createInterface(fs.createReadStream(sshConfigPath)) for await (const line of reader) { - // host format: hostname-port - if (line.includes(`Host ${hostname}-${port}`)) { + if (line.includes(`Host ${host}`)) { // the container ssh info exists canAppendSSHConfig = false break; @@ -195,7 +218,6 @@ export default class RemoteContainer { if (canAppendSSHConfig) { // save the host to the local ssh config file - const host = `${hostname}-${port}` // host: hostname-port const privateKeyPath = this.user.getUserPrivateKeyPath(); const newSShConfigContent = `\nHost ${host}\n HostName ${hostname}\n Port ${port}\n User ${username}\n PreferredAuthentications publickey\n IdentityFile ${privateKeyPath}\n `; @@ -205,21 +227,24 @@ export default class RemoteContainer { } - openRemoteFolder(hostname: string, port: number, username: string, path: string): void { + /** + * 仅支持已经成功连接,并在ssh config file中存储ssh信息的项目连接。 + * + * @host 表示project name + */ + openRemoteFolder(host: string, port: number, username: string, path: string): void { if (vscode.env.remoteName) { // 远程环境,打开local terminal vscode.commands.executeCommand('workbench.action.terminal.newLocal').then(() => { // 获取最后一个打开的终端实例 const terminal = vscode.window.terminals[vscode.window.terminals.length - 1]; if (terminal) { - var host = `${hostname}-${port}` // 在新窗口打开 terminal.sendText(`code --remote ssh-remote+${username}@${host}:${port} ${path} --new-window`) } }) } else { // 本地环境 - var host = `${hostname}-${port}` let terminal = vscode.window.activeTerminal || vscode.window.createTerminal(`Ext Terminal`); terminal.show(true); // 在原窗口打开 @@ -229,8 +254,15 @@ export default class RemoteContainer { } -export async function openProjectWithoutLogging(host: string, port: number, username: string, path: string): Promise { - const command = `code --remote ssh-remote+${username}@${host}:${port} ${path} --reuse-window` +/** + * 打开项目(无须插件登录) + * @param hostname 表示ip + * @param port + * @param username + * @param path + */ +export async function openProjectWithoutLogging(hostname: string, port: number, username: string, path: string): Promise { + const command = `code --remote ssh-remote+${username}@${hostname}:${port} ${path} --reuse-window` let terminal = vscode.window.activeTerminal || vscode.window.createTerminal(`Ext Terminal`); terminal.show(true); terminal.sendText(command);