Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
后端镜像
Tabby
提交
6ce76af9
T
Tabby
项目概览
后端镜像
/
Tabby
通知
41
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
Tabby
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
6ce76af9
编写于
6月 13, 2021
作者:
E
Eugene Pankov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
zone-ified sftp promises
上级
a2ed674b
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
108 addition
and
77 deletion
+108
-77
terminus-core/src/services/vault.service.ts
terminus-core/src/services/vault.service.ts
+3
-12
terminus-core/src/utils.ts
terminus-core/src/utils.ts
+11
-0
terminus-electron/src/services/platform.service.ts
terminus-electron/src/services/platform.service.ts
+3
-13
terminus-ssh/src/api.ts
terminus-ssh/src/api.ts
+79
-5
terminus-ssh/src/components/sftpPanel.component.ts
terminus-ssh/src/components/sftpPanel.component.ts
+12
-47
未找到文件。
terminus-core/src/services/vault.service.ts
浏览文件 @
6ce76af9
...
...
@@ -5,6 +5,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import
{
AsyncSubject
,
Subject
,
Observable
}
from
'
rxjs
'
import
{
UnlockVaultModalComponent
}
from
'
../components/unlockVaultModal.component
'
import
{
NotificationsService
}
from
'
../services/notifications.service
'
import
{
wrapPromise
}
from
'
utils
'
const
PBKDF_ITERATIONS
=
100000
const
PBKDF_DIGEST
=
'
sha512
'
...
...
@@ -120,7 +121,7 @@ export class VaultService {
passphrase
=
await
this
.
getPassphrase
()
}
try
{
return
await
this
.
wrapPromise
(
decryptVault
(
storage
,
passphrase
))
return
await
wrapPromise
(
this
.
zone
,
decryptVault
(
storage
,
passphrase
))
}
catch
(
e
)
{
_rememberedPassphrase
=
null
if
(
e
.
toString
().
includes
(
'
BAD_DECRYPT
'
))
{
...
...
@@ -144,7 +145,7 @@ export class VaultService {
if
(
_rememberedPassphrase
)
{
_rememberedPassphrase
=
passphrase
}
return
this
.
wrapPromise
(
encryptVault
(
vault
,
passphrase
))
return
wrapPromise
(
this
.
zone
,
encryptVault
(
vault
,
passphrase
))
}
async
save
(
vault
:
Vault
,
passphrase
?:
string
):
Promise
<
void
>
{
...
...
@@ -210,14 +211,4 @@ export class VaultService {
isEnabled
():
boolean
{
return
!!
this
.
store
}
private
wrapPromise
<
T
>
(
promise
:
Promise
<
T
>
):
Promise
<
T
>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
promise
.
then
(
result
=>
{
this
.
zone
.
run
(()
=>
resolve
(
result
))
}).
catch
(
error
=>
{
this
.
zone
.
run
(()
=>
reject
(
error
))
})
})
}
}
terminus-core/src/utils.ts
浏览文件 @
6ce76af9
import
*
as
os
from
'
os
'
import
{
NgZone
}
from
'
@angular/core
'
export
const
WIN_BUILD_CONPTY_SUPPORTED
=
17692
export
const
WIN_BUILD_CONPTY_STABLE
=
18309
...
...
@@ -20,3 +21,13 @@ export function getCSSFontFamily (config: any): string {
fonts
=
fonts
.
map
(
x
=>
`"
${
x
}
"`
)
return
fonts
.
join
(
'
,
'
)
}
export
function
wrapPromise
<
T
>
(
zone
:
NgZone
,
promise
:
Promise
<
T
>
):
Promise
<
T
>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
promise
.
then
(
result
=>
{
zone
.
run
(()
=>
resolve
(
result
))
}).
catch
(
error
=>
{
zone
.
run
(()
=>
reject
(
error
))
})
})
}
terminus-electron/src/services/platform.service.ts
浏览文件 @
6ce76af9
...
...
@@ -5,7 +5,7 @@ import * as os from 'os'
import
promiseIpc
from
'
electron-promise-ipc
'
import
{
execFile
}
from
'
mz/child_process
'
import
{
Injectable
,
NgZone
}
from
'
@angular/core
'
import
{
PlatformService
,
ClipboardContent
,
HostAppService
,
Platform
,
ElectronService
,
MenuItemOptions
,
MessageBoxOptions
,
MessageBoxResult
,
FileUpload
,
FileDownload
,
FileUploadOptions
}
from
'
terminus-core
'
import
{
PlatformService
,
ClipboardContent
,
HostAppService
,
Platform
,
ElectronService
,
MenuItemOptions
,
MessageBoxOptions
,
MessageBoxResult
,
FileUpload
,
FileDownload
,
FileUploadOptions
,
wrapPromise
}
from
'
terminus-core
'
const
fontManager
=
require
(
'
fontmanager-redux
'
)
// eslint-disable-line
/* eslint-disable block-scoped-var */
...
...
@@ -181,7 +181,7 @@ export class ElectronPlatformService extends PlatformService {
return
Promise
.
all
(
result
.
filePaths
.
map
(
async
p
=>
{
const
transfer
=
new
ElectronFileUpload
(
p
)
await
this
.
wrapPromise
(
transfer
.
open
())
await
wrapPromise
(
this
.
zone
,
transfer
.
open
())
this
.
fileTransferStarted
.
next
(
transfer
)
return
transfer
}))
...
...
@@ -198,20 +198,10 @@ export class ElectronPlatformService extends PlatformService {
return
null
}
const
transfer
=
new
ElectronFileDownload
(
result
.
filePath
,
size
)
await
this
.
wrapPromise
(
transfer
.
open
())
await
wrapPromise
(
this
.
zone
,
transfer
.
open
())
this
.
fileTransferStarted
.
next
(
transfer
)
return
transfer
}
private
wrapPromise
<
T
>
(
promise
:
Promise
<
T
>
):
Promise
<
T
>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
promise
.
then
(
result
=>
{
this
.
zone
.
run
(()
=>
resolve
(
result
))
}).
catch
(
error
=>
{
this
.
zone
.
run
(()
=>
reject
(
error
))
})
})
}
}
class
ElectronFileUpload
extends
FileUpload
{
...
...
terminus-ssh/src/api.ts
浏览文件 @
6ce76af9
...
...
@@ -5,12 +5,13 @@ import * as sshpk from 'sshpk'
import
colors
from
'
ansi-colors
'
import
stripAnsi
from
'
strip-ansi
'
import
socksv5
from
'
socksv5
'
import
{
Injector
}
from
'
@angular/core
'
import
{
Injector
,
NgZone
}
from
'
@angular/core
'
import
{
NgbModal
}
from
'
@ng-bootstrap/ng-bootstrap
'
import
{
HostAppService
,
Logger
,
NotificationsService
,
Platform
,
PlatformService
}
from
'
terminus-core
'
import
{
HostAppService
,
Logger
,
NotificationsService
,
Platform
,
PlatformService
,
wrapPromise
}
from
'
terminus-core
'
import
{
BaseSession
}
from
'
terminus-terminal
'
import
{
Server
,
Socket
,
createServer
,
createConnection
}
from
'
net
'
import
{
Client
,
ClientChannel
,
SFTPWrapper
}
from
'
ssh2
'
import
type
{
FileEntry
,
Stats
}
from
'
ssh2-streams
'
import
{
Subject
,
Observable
}
from
'
rxjs
'
import
{
ProxyCommandStream
}
from
'
./services/ssh.service
'
import
{
PasswordStorageService
}
from
'
./services/passwordStorage.service
'
...
...
@@ -137,6 +138,77 @@ interface AuthMethod {
path
?:
string
}
export
class
SFTPFileHandle
{
position
=
0
constructor
(
private
sftp
:
SFTPWrapper
,
private
handle
:
Buffer
,
private
zone
:
NgZone
,
)
{
}
read
():
Promise
<
Buffer
>
{
const
buffer
=
Buffer
.
alloc
(
256
*
1024
)
return
wrapPromise
(
this
.
zone
,
new
Promise
((
resolve
,
reject
)
=>
{
while
(
true
)
{
const
wait
=
this
.
sftp
.
read
(
this
.
handle
,
buffer
,
0
,
buffer
.
length
,
this
.
position
,
(
err
,
read
)
=>
{
if
(
err
)
{
reject
(
err
)
return
}
this
.
position
+=
read
resolve
(
buffer
.
slice
(
0
,
read
))
})
if
(
!
wait
)
{
break
}
}
}))
}
write
(
chunk
:
Buffer
):
Promise
<
void
>
{
return
wrapPromise
(
this
.
zone
,
new
Promise
<
void
>
((
resolve
,
reject
)
=>
{
while
(
true
)
{
const
wait
=
this
.
sftp
.
write
(
this
.
handle
,
chunk
,
0
,
chunk
.
length
,
this
.
position
,
err
=>
{
if
(
err
)
{
return
reject
(
err
)
}
this
.
position
+=
chunk
.
length
resolve
()
})
if
(
!
wait
)
{
break
}
}
}))
}
close
():
Promise
<
void
>
{
return
wrapPromise
(
this
.
zone
,
promisify
(
this
.
sftp
.
close
.
bind
(
this
.
sftp
))(
this
.
handle
))
}
}
export
class
SFTPSession
{
constructor
(
private
sftp
:
SFTPWrapper
,
private
zone
:
NgZone
)
{
}
readdir
(
p
:
string
):
Promise
<
FileEntry
[]
>
{
return
wrapPromise
(
this
.
zone
,
promisify
<
FileEntry
[]
>
(
f
=>
this
.
sftp
.
readdir
(
p
,
f
))())
}
readlink
(
p
:
string
):
Promise
<
string
>
{
return
wrapPromise
(
this
.
zone
,
promisify
<
string
>
(
f
=>
this
.
sftp
.
readlink
(
p
,
f
))())
}
stat
(
p
:
string
):
Promise
<
Stats
>
{
return
wrapPromise
(
this
.
zone
,
promisify
<
Stats
>
(
f
=>
this
.
sftp
.
stat
(
p
,
f
))())
}
async
open
(
p
:
string
,
mode
:
string
):
Promise
<
SFTPFileHandle
>
{
const
handle
=
await
wrapPromise
(
this
.
zone
,
promisify
<
Buffer
>
(
f
=>
this
.
sftp
.
open
(
p
,
mode
,
f
))())
return
new
SFTPFileHandle
(
this
.
sftp
,
handle
,
this
.
zone
)
}
}
export
class
SSHSession
extends
BaseSession
{
scripts
?:
LoginScript
[]
shell
?:
ClientChannel
...
...
@@ -161,6 +233,7 @@ export class SSHSession extends BaseSession {
private
hostApp
:
HostAppService
private
platform
:
PlatformService
private
notifications
:
NotificationsService
private
zone
:
NgZone
constructor
(
injector
:
Injector
,
...
...
@@ -172,6 +245,7 @@ export class SSHSession extends BaseSession {
this
.
hostApp
=
injector
.
get
(
HostAppService
)
this
.
platform
=
injector
.
get
(
PlatformService
)
this
.
notifications
=
injector
.
get
(
NotificationsService
)
this
.
zone
=
injector
.
get
(
NgZone
)
this
.
scripts
=
connection
.
scripts
??
[]
this
.
destroyed$
.
subscribe
(()
=>
{
...
...
@@ -223,11 +297,11 @@ export class SSHSession extends BaseSession {
this
.
remainingAuthMethods
.
push
({
type
:
'
hostbased
'
})
}
async
openSFTP
():
Promise
<
SFTP
Wrapper
>
{
async
openSFTP
():
Promise
<
SFTP
Session
>
{
if
(
!
this
.
sftp
)
{
this
.
sftp
=
await
promisify
<
SFTPWrapper
>
(
f
=>
this
.
ssh
.
sftp
(
f
))(
)
this
.
sftp
=
await
wrapPromise
(
this
.
zone
,
promisify
<
SFTPWrapper
>
(
f
=>
this
.
ssh
.
sftp
(
f
))()
)
}
return
this
.
sftp
return
new
SFTPSession
(
this
.
sftp
,
this
.
zone
)
}
async
start
():
Promise
<
void
>
{
...
...
terminus-ssh/src/components/sftpPanel.component.ts
浏览文件 @
6ce76af9
import
{
Component
,
Input
,
Output
,
EventEmitter
}
from
'
@angular/core
'
import
{
SFTPWrapper
}
from
'
ssh2
'
import
type
{
FileEntry
,
Stats
}
from
'
ssh2-streams
'
import
{
promisify
}
from
'
util
'
import
{
SSHSession
}
from
'
../api
'
import
type
{
FileEntry
}
from
'
ssh2-streams
'
import
{
SSHSession
,
SFTPSession
}
from
'
../api
'
import
*
as
path
from
'
path
'
import
*
as
C
from
'
constants
'
import
{
FileUpload
,
PlatformService
}
from
'
terminus-core
'
...
...
@@ -21,7 +19,7 @@ interface PathSegment {
export
class
SFTPPanelComponent
{
@
Input
()
session
:
SSHSession
@
Output
()
closed
=
new
EventEmitter
<
void
>
()
sftp
:
SFTP
Wrapper
sftp
:
SFTP
Session
fileList
:
FileEntry
[]
|
null
=
null
path
=
'
/
'
pathSegments
:
PathSegment
[]
=
[]
...
...
@@ -49,8 +47,7 @@ export class SFTPPanelComponent {
}
this
.
fileList
=
null
this
.
fileList
=
await
promisify
<
FileEntry
[]
>
(
f
=>
this
.
sftp
.
readdir
(
this
.
path
,
f
))()
console
.
log
(
this
.
fileList
)
this
.
fileList
=
await
this
.
sftp
.
readdir
(
this
.
path
)
const
dirKey
=
a
=>
(
a
.
attrs
.
mode
&
C
.
S_IFDIR
)
===
C
.
S_IFDIR
?
1
:
0
this
.
fileList
.
sort
((
a
,
b
)
=>
...
...
@@ -77,8 +74,8 @@ export class SFTPPanelComponent {
if
((
item
.
attrs
.
mode
&
C
.
S_IFDIR
)
===
C
.
S_IFDIR
)
{
this
.
navigate
(
path
.
join
(
this
.
path
,
item
.
filename
))
}
else
if
((
item
.
attrs
.
mode
&
C
.
S_IFLNK
)
===
C
.
S_IFLNK
)
{
const
target
=
await
promisify
<
string
>
(
f
=>
this
.
sftp
.
readlink
(
itemPath
,
f
))(
)
const
stat
=
await
promisify
<
Stats
>
(
f
=>
this
.
sftp
.
stat
(
target
,
f
))(
)
const
target
=
await
this
.
sftp
.
readlink
(
itemPath
)
const
stat
=
await
this
.
sftp
.
stat
(
target
)
if
(
stat
.
isDirectory
())
{
this
.
navigate
(
itemPath
)
}
else
{
...
...
@@ -104,30 +101,15 @@ export class SFTPPanelComponent {
async
uploadOne
(
transfer
:
FileUpload
):
Promise
<
void
>
{
const
itemPath
=
path
.
join
(
this
.
path
,
transfer
.
getName
())
try
{
const
handle
=
await
promisify
<
Buffer
>
(
f
=>
this
.
sftp
.
open
(
itemPath
,
'
w
'
,
f
))()
let
position
=
0
const
handle
=
await
this
.
sftp
.
open
(
itemPath
,
'
w
'
)
while
(
true
)
{
const
chunk
=
await
transfer
.
read
()
if
(
!
chunk
.
length
)
{
break
}
const
p
=
position
await
new
Promise
<
void
>
((
resolve
,
reject
)
=>
{
while
(
true
)
{
const
wait
=
this
.
sftp
.
write
(
handle
,
chunk
,
0
,
chunk
.
length
,
p
,
err
=>
{
if
(
err
)
{
return
reject
(
err
)
}
resolve
()
})
if
(
!
wait
)
{
break
}
}
})
position
+=
chunk
.
length
await
handle
.
write
(
chunk
)
}
this
.
sftp
.
close
(
handle
,
()
=>
null
)
handle
.
close
(
)
transfer
.
close
()
}
catch
(
e
)
{
transfer
.
cancel
()
...
...
@@ -141,33 +123,16 @@ export class SFTPPanelComponent {
return
}
try
{
const
handle
=
await
promisify
<
Buffer
>
(
f
=>
this
.
sftp
.
open
(
itemPath
,
'
r
'
,
f
))()
const
buffer
=
Buffer
.
alloc
(
256
*
1024
)
let
position
=
0
const
handle
=
await
this
.
sftp
.
open
(
itemPath
,
'
r
'
)
while
(
true
)
{
const
p
=
position
const
chunk
:
Buffer
=
await
new
Promise
((
resolve
,
reject
)
=>
{
while
(
true
)
{
const
wait
=
this
.
sftp
.
read
(
handle
,
buffer
,
0
,
buffer
.
length
,
p
,
(
err
,
read
)
=>
{
if
(
err
)
{
reject
(
err
)
return
}
resolve
(
buffer
.
slice
(
0
,
read
))
})
if
(
!
wait
)
{
break
}
}
})
const
chunk
=
await
handle
.
read
()
if
(
!
chunk
.
length
)
{
break
}
await
transfer
.
write
(
chunk
)
position
+=
chunk
.
length
}
transfer
.
close
()
this
.
sftp
.
close
(
handle
,
()
=>
null
)
handle
.
close
(
)
}
catch
(
e
)
{
transfer
.
cancel
()
throw
e
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录