@maiyunnet/kebab 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1 -1
- package/lib/sql.js +1 -3
- package/lib/text.js +5 -1
- package/package.json +1 -1
- package/tsconfig.json +1 -1
- package/index.ts +0 -33
- package/lib/buffer.ts +0 -152
- package/lib/captcha.ts +0 -63
- package/lib/consistent.ts +0 -219
- package/lib/core.ts +0 -880
- package/lib/crypto.ts +0 -384
- package/lib/db.ts +0 -719
- package/lib/dns.ts +0 -405
- package/lib/fs.ts +0 -527
- package/lib/jwt.ts +0 -276
- package/lib/kv.ts +0 -1489
- package/lib/lan.ts +0 -87
- package/lib/net/formdata.ts +0 -166
- package/lib/net/request.ts +0 -150
- package/lib/net/response.ts +0 -59
- package/lib/net.ts +0 -662
- package/lib/s3.ts +0 -235
- package/lib/scan.ts +0 -364
- package/lib/session.ts +0 -230
- package/lib/sql.ts +0 -1151
- package/lib/ssh/sftp.ts +0 -508
- package/lib/ssh/shell.ts +0 -123
- package/lib/ssh.ts +0 -191
- package/lib/text.ts +0 -615
- package/lib/time.ts +0 -254
- package/lib/ws.ts +0 -523
- package/lib/zip.ts +0 -447
- package/lib/zlib.ts +0 -350
- package/main.ts +0 -27
- package/sys/child.ts +0 -678
- package/sys/cmd.ts +0 -225
- package/sys/ctr.ts +0 -904
- package/sys/master.ts +0 -355
- package/sys/mod.ts +0 -1871
- package/sys/route.ts +0 -1113
- package/types/index.d.ts +0 -283
- package/www/example/ctr/main.ts +0 -9
- package/www/example/ctr/middle.ts +0 -26
- package/www/example/ctr/test.ts +0 -3218
- package/www/example/mod/test.ts +0 -47
- package/www/example/mod/testdata.ts +0 -30
- package/www/example/ws/mproxy.ts +0 -16
- package/www/example/ws/rproxy.ts +0 -14
- package/www/example/ws/test.ts +0 -36
package/lib/ssh/sftp.ts
DELETED
|
@@ -1,508 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
-
* Date: 2019-6-10 12:06
|
|
4
|
-
* Last: 2020-4-11 09:28:11, 2022-09-11 17:15:38, 2023-4-24 21:43:42
|
|
5
|
-
*/
|
|
6
|
-
import * as stream from 'stream';
|
|
7
|
-
import * as ssh2 from 'ssh2';
|
|
8
|
-
// --- 库和定义 ---
|
|
9
|
-
import * as core from '~/lib/core';
|
|
10
|
-
import * as text from '~/lib/text';
|
|
11
|
-
|
|
12
|
-
export class Connection {
|
|
13
|
-
|
|
14
|
-
/** --- 连接对象 --- */
|
|
15
|
-
private readonly _client: ssh2.SFTPWrapper;
|
|
16
|
-
|
|
17
|
-
/** --- 当前路径,以 / 结尾 --- */
|
|
18
|
-
private _path: string;
|
|
19
|
-
|
|
20
|
-
public constructor(sftp: ssh2.SFTPWrapper, path: string) {
|
|
21
|
-
this._client = sftp;
|
|
22
|
-
this._path = path;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
public getContent(path: string, options?: {
|
|
26
|
-
'start'?: number;
|
|
27
|
-
'end'?: number;
|
|
28
|
-
}): Promise<Buffer | null>;
|
|
29
|
-
public getContent(path: string, options: BufferEncoding | {
|
|
30
|
-
'encoding': BufferEncoding;
|
|
31
|
-
'start'?: number;
|
|
32
|
-
'end'?: number;
|
|
33
|
-
}): Promise<string | null>;
|
|
34
|
-
/**
|
|
35
|
-
* --- 读取完整文件或一段 ---
|
|
36
|
-
* @param path 文件路径
|
|
37
|
-
* @param options 编码或选项
|
|
38
|
-
*/
|
|
39
|
-
public getContent(path: string, options?: BufferEncoding | {
|
|
40
|
-
'encoding'?: BufferEncoding;
|
|
41
|
-
'start'?: number;
|
|
42
|
-
'end'?: number;
|
|
43
|
-
}): Promise<Buffer | string | null> {
|
|
44
|
-
path = text.urlResolve(this._path, path);
|
|
45
|
-
if (typeof options === 'string') {
|
|
46
|
-
options = {
|
|
47
|
-
'encoding': options
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
else if (!options) {
|
|
51
|
-
options = {};
|
|
52
|
-
}
|
|
53
|
-
const encoding = options.encoding;
|
|
54
|
-
const start = options.start;
|
|
55
|
-
const end = options.end;
|
|
56
|
-
return new Promise((resolve) => {
|
|
57
|
-
if (start ?? end) {
|
|
58
|
-
const rs = this.createReadStream(path, {
|
|
59
|
-
'encoding': encoding,
|
|
60
|
-
'start': start,
|
|
61
|
-
'end': end
|
|
62
|
-
});
|
|
63
|
-
const data: Buffer[] = [];
|
|
64
|
-
rs.on('data', function(chunk: Buffer) {
|
|
65
|
-
data.push(chunk);
|
|
66
|
-
}).on('end', function() {
|
|
67
|
-
const buf = Buffer.concat(data);
|
|
68
|
-
if (encoding) {
|
|
69
|
-
resolve(buf.toString());
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
resolve(buf);
|
|
73
|
-
}
|
|
74
|
-
}).on('error', function() {
|
|
75
|
-
resolve(null);
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
if (encoding) {
|
|
80
|
-
this._client.readFile(path, {
|
|
81
|
-
'encoding': encoding
|
|
82
|
-
}, function(err, data) {
|
|
83
|
-
if (err) {
|
|
84
|
-
resolve(null);
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
resolve(data);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
this._client.readFile(path, function(err, data) {
|
|
93
|
-
if (err) {
|
|
94
|
-
resolve(null);
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
resolve(data);
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* --- 写入文件内容 ---
|
|
107
|
-
* @param path 文件路径
|
|
108
|
-
* @param data 要写入的内容
|
|
109
|
-
* @param options 选项
|
|
110
|
-
*/
|
|
111
|
-
public putContent(
|
|
112
|
-
path: string,
|
|
113
|
-
data: string | Buffer,
|
|
114
|
-
options: ssh2.WriteFileOptions = {}
|
|
115
|
-
): Promise<boolean> {
|
|
116
|
-
path = text.urlResolve(this._path, path);
|
|
117
|
-
return new Promise((resolve) => {
|
|
118
|
-
this._client.writeFile(path, data, options, function(err) {
|
|
119
|
-
if (err) {
|
|
120
|
-
resolve(false);
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
resolve(true);
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* --- 读取链接的 target ---
|
|
131
|
-
* @param path 要读取的路径
|
|
132
|
-
*/
|
|
133
|
-
public readLink(path: string): Promise<string | null> {
|
|
134
|
-
path = text.urlResolve(this._path, path);
|
|
135
|
-
return new Promise((resolve) => {
|
|
136
|
-
this._client.readlink(path, function(err, target) {
|
|
137
|
-
if (err) {
|
|
138
|
-
resolve(null);
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
resolve(target);
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* --- 把源文件创建一个 link ---
|
|
149
|
-
* @param filePath 源文件
|
|
150
|
-
* @param linkPath 连接路径
|
|
151
|
-
*/
|
|
152
|
-
public symlink(filePath: string, linkPath: string): Promise<boolean> {
|
|
153
|
-
filePath = text.urlResolve(this._path, filePath);
|
|
154
|
-
linkPath = text.urlResolve(this._path, linkPath);
|
|
155
|
-
return new Promise((resolve) => {
|
|
156
|
-
this._client.symlink(filePath, linkPath, function(err) {
|
|
157
|
-
if (err) {
|
|
158
|
-
resolve(false);
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
resolve(true);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* --- 删除一个文件 ---
|
|
169
|
-
* @param path 要删除的文件路径
|
|
170
|
-
*/
|
|
171
|
-
public async unlink(path: string): Promise<boolean> {
|
|
172
|
-
path = text.urlResolve(this._path, path);
|
|
173
|
-
for (let i = 0; i < 2; ++i) {
|
|
174
|
-
const bol = await this._unlink(path);
|
|
175
|
-
if (bol) {
|
|
176
|
-
return true;
|
|
177
|
-
}
|
|
178
|
-
await core.sleep(250);
|
|
179
|
-
}
|
|
180
|
-
return this._unlink(path);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/** --- unlink 的删除的 promise 实现 --- */
|
|
184
|
-
private _unlink(path: string): Promise<boolean> {
|
|
185
|
-
return new Promise((resolve) => {
|
|
186
|
-
this._client.unlink(path, function(err) {
|
|
187
|
-
if (err) {
|
|
188
|
-
resolve(false);
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
resolve(true);
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* --- 获取对象是否存在,存在则返回 stats 对象,否则返回 null ---
|
|
199
|
-
* @param path 对象路径
|
|
200
|
-
*/
|
|
201
|
-
public stats(path: string): Promise<ssh2.Stats | null> {
|
|
202
|
-
path = text.urlResolve(this._path, path);
|
|
203
|
-
return new Promise((resolve) => {
|
|
204
|
-
this._client.lstat(path, function(err, stat) {
|
|
205
|
-
if (err) {
|
|
206
|
-
resolve(null);
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
resolve(stat);
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* --- 判断是否是目录或目录是否存在,是的话返回 stats ---
|
|
217
|
-
* @param path 判断路径
|
|
218
|
-
*/
|
|
219
|
-
public async isDir(path: string): Promise<ssh2.Stats | false> {
|
|
220
|
-
const pstats = await this.stats(path);
|
|
221
|
-
if (!pstats?.isDirectory()) {
|
|
222
|
-
return false;
|
|
223
|
-
}
|
|
224
|
-
return pstats;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* --- 判断是否是文件或文件是否存在,是的话返回 stats ---
|
|
229
|
-
* @param path 判断路径
|
|
230
|
-
*/
|
|
231
|
-
public async isFile(path: string): Promise<ssh2.Stats | false> {
|
|
232
|
-
const pstats = await this.stats(path);
|
|
233
|
-
if (!pstats?.isFile()) {
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
return pstats;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* --- 深度创建目录,如果最末目录存在,则自动创建成功 ---
|
|
241
|
-
* @param path 要创建的路径,如 /a/b/c/
|
|
242
|
-
* @param mode 权限
|
|
243
|
-
*/
|
|
244
|
-
public async mkdir(path: string, mode: number = 0o755): Promise<boolean> {
|
|
245
|
-
path = text.urlResolve(this._path, path);
|
|
246
|
-
if (await this.isDir(path)) {
|
|
247
|
-
return true;
|
|
248
|
-
}
|
|
249
|
-
if (path.endsWith('/')) {
|
|
250
|
-
path.slice(0, -1);
|
|
251
|
-
}
|
|
252
|
-
const lio = path.lastIndexOf('/');
|
|
253
|
-
if (!(await this.mkdir(path.slice(0, lio), mode))) {
|
|
254
|
-
return false;
|
|
255
|
-
}
|
|
256
|
-
if (!(await new Promise((resolve) => {
|
|
257
|
-
this._client.mkdir(path.slice(0, lio), {
|
|
258
|
-
'mode': mode
|
|
259
|
-
}, function(err) {
|
|
260
|
-
if (err) {
|
|
261
|
-
resolve(false);
|
|
262
|
-
}
|
|
263
|
-
else {
|
|
264
|
-
resolve(true);
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
}))) {
|
|
268
|
-
return false;
|
|
269
|
-
}
|
|
270
|
-
return true;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* --- 删除一个空目录 ---
|
|
275
|
-
* @param path 要删除的目录路径
|
|
276
|
-
*/
|
|
277
|
-
public async rmdir(path: string): Promise<boolean> {
|
|
278
|
-
path = text.urlResolve(this._path, path);
|
|
279
|
-
if (!(await this.isDir(path))) {
|
|
280
|
-
return true;
|
|
281
|
-
}
|
|
282
|
-
return new Promise((resolve) => {
|
|
283
|
-
this._client.rmdir(path, function(err) {
|
|
284
|
-
if (err) {
|
|
285
|
-
resolve(false);
|
|
286
|
-
}
|
|
287
|
-
else {
|
|
288
|
-
resolve(true);
|
|
289
|
-
}
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* --- Danger 危险:危险函数,尽量不要使用 ---
|
|
296
|
-
* --- This f**king is a dangerous function, please don't use it ---
|
|
297
|
-
* --- 删除一个非空目录 ---
|
|
298
|
-
*/
|
|
299
|
-
public async rmdirDeep(path: string): Promise<boolean> {
|
|
300
|
-
path = text.urlResolve(this._path, path);
|
|
301
|
-
if (!path.endsWith('/')) {
|
|
302
|
-
path += '/';
|
|
303
|
-
}
|
|
304
|
-
const list = await this.readDir(path);
|
|
305
|
-
for (const item of list) {
|
|
306
|
-
if (item.filename === '.' || item.filename === '..') {
|
|
307
|
-
continue;
|
|
308
|
-
}
|
|
309
|
-
const stat = await this.stats(item.filename);
|
|
310
|
-
if (!stat) {
|
|
311
|
-
return false;
|
|
312
|
-
}
|
|
313
|
-
if (stat.isDirectory()) {
|
|
314
|
-
// --- 目录 ---
|
|
315
|
-
const rtn = await this.rmdirDeep(path + item.filename);
|
|
316
|
-
if (!rtn) {
|
|
317
|
-
return false;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
else {
|
|
321
|
-
const rtn = await this.unlink(path + item.filename);
|
|
322
|
-
if (!rtn) {
|
|
323
|
-
return false;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return this.rmdir(path);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* --- 修改权限 ---
|
|
332
|
-
* @param path 要修改的路径
|
|
333
|
-
* @param mode 权限
|
|
334
|
-
*/
|
|
335
|
-
public chmod(path: string, mode: string | number): Promise<boolean> {
|
|
336
|
-
path = text.urlResolve(this._path, path);
|
|
337
|
-
return new Promise((resolve) => {
|
|
338
|
-
this._client.chmod(path, mode, function(err) {
|
|
339
|
-
if (err) {
|
|
340
|
-
resolve(false);
|
|
341
|
-
}
|
|
342
|
-
else {
|
|
343
|
-
resolve(true);
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* --- 重命名/移动 文件文件夹 ---
|
|
351
|
-
* @param oldPath 老名
|
|
352
|
-
* @param newPath 新名
|
|
353
|
-
*/
|
|
354
|
-
public rename(oldPath: string, newPath: string): Promise<boolean> {
|
|
355
|
-
oldPath = text.urlResolve(this._path, oldPath);
|
|
356
|
-
newPath = text.urlResolve(this._path, newPath);
|
|
357
|
-
return new Promise((resolve) => {
|
|
358
|
-
this._client.rename(oldPath, newPath, function(err) {
|
|
359
|
-
if (err) {
|
|
360
|
-
resolve(false);
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
resolve(true);
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* --- 获取文件夹下文件列表 ---
|
|
371
|
-
* @param path 文件夹路径
|
|
372
|
-
*/
|
|
373
|
-
public readDir(path: string): Promise<ssh2.FileEntry[]> {
|
|
374
|
-
path = text.urlResolve(this._path, path);
|
|
375
|
-
return new Promise((resolve) => {
|
|
376
|
-
this._client.readdir(path, function(err, files) {
|
|
377
|
-
if (err) {
|
|
378
|
-
resolve([]);
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
resolve(files);
|
|
382
|
-
}
|
|
383
|
-
});
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* --- 读取文件流 ---
|
|
389
|
-
* @param path 文件地址
|
|
390
|
-
*/
|
|
391
|
-
public createReadStream(path: string, options?: ssh2.ReadStreamOptions): stream.Readable {
|
|
392
|
-
path = text.urlResolve(this._path, path);
|
|
393
|
-
return this._client.createReadStream(path, options);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* --- 读取文件写入到流,并等待写入完成 ---
|
|
398
|
-
* @param path 文件地址
|
|
399
|
-
* @param destination 要写入的流
|
|
400
|
-
* @param options 写入后是否终止写入流,默认终止
|
|
401
|
-
*/
|
|
402
|
-
public pipe<T extends NodeJS.WritableStream>(path: string, destination: T, options: {
|
|
403
|
-
'end'?: boolean;
|
|
404
|
-
} = {}): Promise<boolean> {
|
|
405
|
-
path = text.urlResolve(this._path, path);
|
|
406
|
-
return new Promise((resolve) => {
|
|
407
|
-
this._client.createReadStream(path).on('error', function() {
|
|
408
|
-
resolve(false);
|
|
409
|
-
}).on('end', function() {
|
|
410
|
-
resolve(true);
|
|
411
|
-
}).pipe(destination, options);
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* --- 创建写入文件的流 ---
|
|
417
|
-
* @param path 文件地址
|
|
418
|
-
* @param options 编码或配置
|
|
419
|
-
*/
|
|
420
|
-
public createWriteStream(path: string, options?: BufferEncoding | ssh2.WriteStreamOptions): stream.Writable {
|
|
421
|
-
if (typeof options === 'string') {
|
|
422
|
-
options = {
|
|
423
|
-
'encoding': options
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
else if (!options) {
|
|
427
|
-
options = {};
|
|
428
|
-
}
|
|
429
|
-
return this._client.createWriteStream(path, options);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* --- 获取当前目录,末尾不带 / ---
|
|
434
|
-
* @return string
|
|
435
|
-
*/
|
|
436
|
-
public pwd(): string {
|
|
437
|
-
return this._path.slice(0, -1);
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* --- 下载文件到本地 ---
|
|
442
|
-
* @param remoteFile 远程路径
|
|
443
|
-
* @param localFile 本地路径
|
|
444
|
-
* @param options 选项
|
|
445
|
-
*/
|
|
446
|
-
public downloadFile(
|
|
447
|
-
remoteFile: string,
|
|
448
|
-
localFile: string,
|
|
449
|
-
options: ssh2.TransferOptions = {}
|
|
450
|
-
): Promise<boolean> {
|
|
451
|
-
remoteFile = text.urlResolve(this._path, remoteFile);
|
|
452
|
-
return new Promise((resolve) => {
|
|
453
|
-
this._client.fastGet(remoteFile, localFile, options, function(err) {
|
|
454
|
-
if (err) {
|
|
455
|
-
resolve(false);
|
|
456
|
-
}
|
|
457
|
-
else {
|
|
458
|
-
resolve(true);
|
|
459
|
-
}
|
|
460
|
-
});
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* --- 上传本地文件到远程 ---
|
|
466
|
-
* @param localFile 本地绝对路径
|
|
467
|
-
* @param remoteFile
|
|
468
|
-
* @return bool
|
|
469
|
-
*/
|
|
470
|
-
public uploadFile(
|
|
471
|
-
localFile: string,
|
|
472
|
-
remoteFile: string,
|
|
473
|
-
options: ssh2.TransferOptions = {}
|
|
474
|
-
): Promise<boolean> {
|
|
475
|
-
remoteFile = text.urlResolve(this._path, remoteFile);
|
|
476
|
-
return new Promise((resolve) => {
|
|
477
|
-
this._client.fastPut(localFile, remoteFile, options, function(err) {
|
|
478
|
-
if (err) {
|
|
479
|
-
resolve(false);
|
|
480
|
-
}
|
|
481
|
-
else {
|
|
482
|
-
resolve(true);
|
|
483
|
-
}
|
|
484
|
-
});
|
|
485
|
-
});
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* --- 进入一个目录(不存在也能进入,需要自行判断) ---
|
|
490
|
-
* --- 返回进入后的路径值 ---
|
|
491
|
-
* @param dir 相对路径或绝对路径
|
|
492
|
-
*/
|
|
493
|
-
public cd(dir: string): string {
|
|
494
|
-
this._path = text.urlResolve(this._path, dir);
|
|
495
|
-
if (!this._path.endsWith('/')) {
|
|
496
|
-
this._path += '/';
|
|
497
|
-
}
|
|
498
|
-
return this._path;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* --- 关闭当前频道 ---
|
|
503
|
-
*/
|
|
504
|
-
public close(): void {
|
|
505
|
-
this._client.end();
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
}
|
package/lib/ssh/shell.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
-
* Date: 2019-6-8 22:13
|
|
4
|
-
* Last: 2020-4-10 16:08:32, 2022-12-30 00:03:40, 2023-4-22 21:06:57
|
|
5
|
-
*/
|
|
6
|
-
import * as ssh2 from 'ssh2';
|
|
7
|
-
import * as lCore from '~/lib/core';
|
|
8
|
-
|
|
9
|
-
export class Connection {
|
|
10
|
-
|
|
11
|
-
/** --- 连接对象 --- */
|
|
12
|
-
private readonly _client: ssh2.ClientChannel;
|
|
13
|
-
|
|
14
|
-
public constructor(stream: ssh2.ClientChannel) {
|
|
15
|
-
this._client = stream;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* --- 发送指令 ---
|
|
20
|
-
* @param cmd 指令
|
|
21
|
-
* @param encoding 编码
|
|
22
|
-
*/
|
|
23
|
-
public send(cmd: string | Buffer, encoding?: BufferEncoding): Promise<boolean> {
|
|
24
|
-
return new Promise((resolve) => {
|
|
25
|
-
const cb = (e: any): void => {
|
|
26
|
-
if (e) {
|
|
27
|
-
resolve(false);
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
resolve(true);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
if (encoding) {
|
|
34
|
-
this._client.write(cmd, encoding, cb);
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
this._client.write(cmd, cb);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* --- 发送带换行的内容(发送并执行) ---
|
|
44
|
-
* @param cmd 指令
|
|
45
|
-
* @param encoding 编码
|
|
46
|
-
*/
|
|
47
|
-
public async sendLine(cmd: string, encoding?: BufferEncoding): Promise<boolean> {
|
|
48
|
-
return this.send(cmd + '\n', encoding);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* --- 发送 Enter 键 ---
|
|
53
|
-
*/
|
|
54
|
-
public async sendEnter(): Promise<boolean> {
|
|
55
|
-
return this.send('\n');
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* --- 发送 Tab 键 ---
|
|
60
|
-
*/
|
|
61
|
-
public async sendTab(): Promise<boolean> {
|
|
62
|
-
return this.send('\t');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* --- 发送中断 ---
|
|
67
|
-
*/
|
|
68
|
-
public async sendCtrlC(): Promise<boolean> {
|
|
69
|
-
return this.send('\x03');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* --- 关闭 shell ---
|
|
74
|
-
* @param cmd 命令
|
|
75
|
-
* @param encoding 编码
|
|
76
|
-
*/
|
|
77
|
-
public close(cmd?: string | Buffer, encoding?: BufferEncoding): Promise<void> {
|
|
78
|
-
return new Promise((resolve) => {
|
|
79
|
-
if (encoding) {
|
|
80
|
-
this._client.end(cmd, encoding, () => {
|
|
81
|
-
resolve();
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
this._client.end(cmd, () => {
|
|
86
|
-
resolve();
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* --- 获取返回值 ---
|
|
94
|
-
* @param tryCount 如果无知重试次数,1 次为 10 毫秒 ---
|
|
95
|
-
*/
|
|
96
|
-
public async getContent(tryCount: number = 10): Promise<Buffer> {
|
|
97
|
-
let nowCount: number = 0;
|
|
98
|
-
let data: Buffer = Buffer.from('');
|
|
99
|
-
while (true) {
|
|
100
|
-
const r: Buffer | null = this._client.read();
|
|
101
|
-
if (r !== null) {
|
|
102
|
-
data = Buffer.concat([data, r], data.byteLength + r.byteLength);
|
|
103
|
-
nowCount = 0;
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
++nowCount;
|
|
107
|
-
if (nowCount === tryCount) {
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
110
|
-
await lCore.sleep(10);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return data;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* --- 获取响应读取流对象 ---
|
|
118
|
-
*/
|
|
119
|
-
public getStream(): ssh2.ClientChannel {
|
|
120
|
-
return this._client;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
}
|