added a winscp hotkey - fixes #2938

This commit is contained in:
Eugene Pankov 2021-06-05 12:32:38 +02:00
parent 03bf6e5302
commit c2ca127574
No known key found for this signature in database
GPG key ID: 5896FCBBDD1CF4F4
6 changed files with 79 additions and 77 deletions

View file

@ -62,6 +62,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
case 'restart-ssh-session':
this.reconnect()
break
case 'launch-winscp':
if (this.session) {
this.ssh.launchWinSCP(this.session)
}
break
}
})

View file

@ -13,6 +13,10 @@ export class SSHHotkeyProvider extends HotkeyProvider {
id: 'restart-ssh-session',
name: 'Restart current SSH session',
},
{
id: 'launch-winscp',
name: 'Launch WinSCP for current SSH session',
},
]
async provide (): Promise<HotkeyDescription[]> {

View file

@ -19,7 +19,7 @@ import { SSHConfigProvider } from './config'
import { SSHSettingsTabProvider } from './settings'
import { RecoveryProvider } from './recoveryProvider'
import { SSHHotkeyProvider } from './hotkeys'
import { WinSCPContextMenu } from './winSCPIntegration'
import { WinSCPContextMenu } from './tabContextMenu'
import { SSHCLIHandler } from './cli'
/** @hidden */

View file

@ -5,7 +5,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { Client } from 'ssh2'
import { exec } from 'child_process'
import { Subject, Observable } from 'rxjs'
import { Logger, LogService, AppService, SelectorOption, ConfigService, NotificationsService } from 'terminus-core'
import { Logger, LogService, AppService, SelectorOption, ConfigService, NotificationsService, HostAppService, Platform, PlatformService } from 'terminus-core'
import { SettingsTabComponent } from 'terminus-settings'
import { ALGORITHM_BLACKLIST, ForwardedPort, SSHConnection, SSHSession } from '../api'
import { PromptModalComponent } from '../components/promptModal.component'
@ -16,6 +16,7 @@ import { ChildProcess } from 'node:child_process'
@Injectable({ providedIn: 'root' })
export class SSHService {
private logger: Logger
private detectedWinSCPPath: string | null
private constructor (
private injector: Injector,
@ -26,8 +27,13 @@ export class SSHService {
private notifications: NotificationsService,
private app: AppService,
private config: ConfigService,
hostApp: HostAppService,
private platform: PlatformService,
) {
this.logger = log.create('ssh')
if (hostApp.platform === Platform.Windows) {
this.detectedWinSCPPath = platform.getWinSCPPath()
}
}
createSession (connection: SSHConnection): SSHSession {
@ -277,6 +283,33 @@ export class SSHService {
this.config.save()
return this.connect(connection)
}
getWinSCPPath (): string|undefined {
return this.detectedWinSCPPath ?? this.config.store.ssh.winSCPPath
}
async getWinSCPURI (connection: SSHConnection): Promise<string> {
let uri = `scp://${connection.user}`
const password = await this.passwordStorage.loadPassword(connection)
if (password) {
uri += ':' + encodeURIComponent(password)
}
uri += `@${connection.host}:${connection.port}/`
return uri
}
async launchWinSCP (session: SSHSession): Promise<void> {
const path = this.getWinSCPPath()
if (!path) {
return
}
const args = [await this.getWinSCPURI(session.connection)]
if (session.activePrivateKey) {
args.push('/privatekey')
args.push(session.activePrivateKey)
}
this.platform.exec(path, args)
}
}
export class ProxyCommandStream extends Duplex {

View file

@ -0,0 +1,35 @@
import { Injectable } from '@angular/core'
import { BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, HostAppService, Platform, MenuItemOptions } from 'terminus-core'
import { SSHTabComponent } from './components/sshTab.component'
import { SSHService } from './services/ssh.service'
/** @hidden */
@Injectable()
export class WinSCPContextMenu extends TabContextMenuItemProvider {
weight = 10
constructor (
private hostApp: HostAppService,
private ssh: SSHService,
) {
super()
}
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemOptions[]> {
if (!(tab instanceof SSHTabComponent) || !tab.connection) {
return []
}
if (this.hostApp.platform !== Platform.Windows || tabHeader || !this.ssh.getWinSCPPath()) {
return []
}
return [
{
label: 'Launch WinSCP',
click: (): void => {
this.ssh.launchWinSCP(tab.session!)
},
},
]
}
}

View file

@ -1,75 +0,0 @@
import { Injectable } from '@angular/core'
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, HostAppService, Platform, PlatformService, MenuItemOptions } from 'terminus-core'
import { SSHTabComponent } from './components/sshTab.component'
import { PasswordStorageService } from './services/passwordStorage.service'
import { SSHConnection, SSHSession } from './api'
/** @hidden */
@Injectable()
export class WinSCPContextMenu extends TabContextMenuItemProvider {
weight = 10
private detectedPath: string | null
constructor (
private hostApp: HostAppService,
private config: ConfigService,
private platform: PlatformService,
private passwordStorage: PasswordStorageService,
) {
super()
if (hostApp.platform !== Platform.Windows) {
return
}
this.detectedPath = platform.getWinSCPPath()
}
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemOptions[]> {
if (this.hostApp.platform !== Platform.Windows || tabHeader) {
return []
}
if (!this.getPath()) {
return []
}
if (!(tab instanceof SSHTabComponent) || !tab.connection) {
return []
}
return [
{
label: 'Launch WinSCP',
click: (): void => {
this.launchWinSCP(tab.session!)
},
},
]
}
getPath (): string|undefined {
return this.detectedPath ?? this.config.store.ssh.winSCPPath
}
async getURI (connection: SSHConnection): Promise<string> {
let uri = `scp://${connection.user}`
const password = await this.passwordStorage.loadPassword(connection)
if (password) {
uri += ':' + encodeURIComponent(password)
}
uri += `@${connection.host}:${connection.port}/`
return uri
}
async launchWinSCP (session: SSHSession): Promise<void> {
const path = this.getPath()
if (!path) {
return
}
const args = [await this.getURI(session.connection)]
if (session.activePrivateKey) {
args.push('/privatekey')
args.push(session.activePrivateKey)
}
this.platform.exec(path, args)
}
}