koishi-plugin-docker-control 0.0.1
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/lib/commands/control.d.ts +9 -0
- package/lib/commands/control.js +202 -0
- package/lib/commands/index.d.ts +14 -0
- package/lib/commands/index.js +224 -0
- package/lib/commands/list.d.ts +6 -0
- package/lib/commands/list.js +269 -0
- package/lib/commands/logs.d.ts +10 -0
- package/lib/commands/logs.js +85 -0
- package/lib/config.d.ts +55 -0
- package/lib/config.js +90 -0
- package/lib/constants.d.ts +26 -0
- package/lib/constants.js +37 -0
- package/lib/index.d.ts +125 -0
- package/lib/index.js +312 -0
- package/lib/service/agent.d.ts +28 -0
- package/lib/service/agent.js +64 -0
- package/lib/service/connector.d.ts +67 -0
- package/lib/service/connector.js +267 -0
- package/lib/service/index.d.ts +65 -0
- package/lib/service/index.js +202 -0
- package/lib/service/monitor.d.ts +38 -0
- package/lib/service/monitor.js +139 -0
- package/lib/service/node.d.ts +119 -0
- package/lib/service/node.js +509 -0
- package/lib/service/notifier.d.ts +33 -0
- package/lib/service/notifier.js +189 -0
- package/lib/types.d.ts +100 -0
- package/lib/types.js +5 -0
- package/lib/utils/format.d.ts +39 -0
- package/lib/utils/format.js +142 -0
- package/lib/utils/logger.d.ts +65 -0
- package/lib/utils/logger.js +89 -0
- package/lib/utils/stream.d.ts +28 -0
- package/lib/utils/stream.js +156 -0
- package/package.json +38 -0
- package/readme.md +96 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 流处理工具
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.streamToString = streamToString;
|
|
7
|
+
exports.stringToStream = stringToStream;
|
|
8
|
+
exports.mergeStreams = mergeStreams;
|
|
9
|
+
exports.throttleStream = throttleStream;
|
|
10
|
+
exports.decodeStream = decodeStream;
|
|
11
|
+
exports.tailStream = tailStream;
|
|
12
|
+
/**
|
|
13
|
+
* 将 Stream 转换为字符串
|
|
14
|
+
*/
|
|
15
|
+
async function streamToString(stream) {
|
|
16
|
+
const chunks = [];
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
stream.on('data', (chunk) => chunks.push(chunk));
|
|
19
|
+
stream.on('end', () => {
|
|
20
|
+
const buffer = Buffer.concat(chunks);
|
|
21
|
+
resolve(buffer.toString('utf8'));
|
|
22
|
+
});
|
|
23
|
+
stream.on('error', reject);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 将字符串转换为 Stream
|
|
28
|
+
*/
|
|
29
|
+
function stringToStream(content, encoding = 'utf8') {
|
|
30
|
+
const { Readable } = require('stream');
|
|
31
|
+
return Readable.from([Buffer.from(content, encoding)]);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 合并多个 Stream
|
|
35
|
+
*/
|
|
36
|
+
function mergeStreams(streams) {
|
|
37
|
+
const { Readable, PassThrough } = require('stream');
|
|
38
|
+
const output = new PassThrough();
|
|
39
|
+
let pending = streams.length;
|
|
40
|
+
if (pending === 0) {
|
|
41
|
+
output.end();
|
|
42
|
+
return output;
|
|
43
|
+
}
|
|
44
|
+
for (const stream of streams) {
|
|
45
|
+
stream.on('data', (chunk) => output.write(chunk));
|
|
46
|
+
stream.on('end', () => {
|
|
47
|
+
pending--;
|
|
48
|
+
if (pending === 0) {
|
|
49
|
+
output.end();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
stream.on('error', (err) => {
|
|
53
|
+
output.destroy(err);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return output;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 限流 Stream
|
|
60
|
+
* 控制数据输出的速度
|
|
61
|
+
*/
|
|
62
|
+
function throttleStream(stream, maxBytesPerSecond) {
|
|
63
|
+
const { PassThrough } = require('stream');
|
|
64
|
+
const output = new PassThrough();
|
|
65
|
+
let bytesWritten = 0;
|
|
66
|
+
let lastTime = Date.now();
|
|
67
|
+
const checkThrottle = () => {
|
|
68
|
+
const now = Date.now();
|
|
69
|
+
const elapsed = now - lastTime;
|
|
70
|
+
if (elapsed >= 1000) {
|
|
71
|
+
bytesWritten = 0;
|
|
72
|
+
lastTime = now;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
stream.on('data', (chunk) => {
|
|
76
|
+
checkThrottle();
|
|
77
|
+
if (bytesWritten + chunk.length > maxBytesPerSecond) {
|
|
78
|
+
// 需要限流,延迟写入
|
|
79
|
+
const delay = Math.ceil(((bytesWritten + chunk.length - maxBytesPerSecond) /
|
|
80
|
+
maxBytesPerSecond) *
|
|
81
|
+
1000);
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
output.write(chunk);
|
|
84
|
+
}, delay);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
output.write(chunk);
|
|
88
|
+
}
|
|
89
|
+
bytesWritten += chunk.length;
|
|
90
|
+
});
|
|
91
|
+
stream.on('end', () => output.end());
|
|
92
|
+
stream.on('error', (err) => output.destroy(err));
|
|
93
|
+
return output;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 解码 Stream (处理 ANSI 转义码)
|
|
97
|
+
*/
|
|
98
|
+
function decodeStream(stream) {
|
|
99
|
+
const { PassThrough } = require('stream');
|
|
100
|
+
const output = new PassThrough();
|
|
101
|
+
let buffer = '';
|
|
102
|
+
stream.on('data', (chunk) => {
|
|
103
|
+
// 解码 UTF-8
|
|
104
|
+
const text = chunk.toString('utf8');
|
|
105
|
+
buffer += text;
|
|
106
|
+
// 按行处理
|
|
107
|
+
const lines = buffer.split('\n');
|
|
108
|
+
buffer = lines.pop() || '';
|
|
109
|
+
for (const line of lines) {
|
|
110
|
+
// 移除 ANSI 转义码
|
|
111
|
+
const cleanLine = line.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]/g, '');
|
|
112
|
+
output.write(cleanLine + '\n');
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
stream.on('end', () => {
|
|
116
|
+
if (buffer) {
|
|
117
|
+
output.write(buffer);
|
|
118
|
+
}
|
|
119
|
+
output.end();
|
|
120
|
+
});
|
|
121
|
+
stream.on('error', (err) => output.destroy(err));
|
|
122
|
+
return output;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 截取 Stream 的最后 N 行
|
|
126
|
+
*/
|
|
127
|
+
function tailStream(stream, maxLines) {
|
|
128
|
+
const { PassThrough } = require('stream');
|
|
129
|
+
const output = new PassThrough();
|
|
130
|
+
const lines = [];
|
|
131
|
+
stream.on('data', (chunk) => {
|
|
132
|
+
const text = chunk.toString('utf8');
|
|
133
|
+
const newLines = text.split('\n');
|
|
134
|
+
// 将新行加入队列
|
|
135
|
+
if (lines.length > 0) {
|
|
136
|
+
lines[lines.length - 1] += newLines[0];
|
|
137
|
+
lines.push(...newLines.slice(1));
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
lines.push(...newLines);
|
|
141
|
+
}
|
|
142
|
+
// 保持最大行数
|
|
143
|
+
while (lines.length > maxLines + 1) {
|
|
144
|
+
lines.shift();
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
stream.on('end', () => {
|
|
148
|
+
// 输出保留的行
|
|
149
|
+
if (lines.length > 1) {
|
|
150
|
+
output.write(lines.slice(1).join('\n'));
|
|
151
|
+
}
|
|
152
|
+
output.end();
|
|
153
|
+
});
|
|
154
|
+
stream.on('error', (err) => output.destroy(err));
|
|
155
|
+
return output;
|
|
156
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "koishi-plugin-docker-control",
|
|
3
|
+
"description": "Koishi 插件 - 通过 SSH 控制 Docker 容器",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"typings": "lib/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib",
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"dev": "tsc -w"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"chatbot",
|
|
18
|
+
"koishi",
|
|
19
|
+
"plugin",
|
|
20
|
+
"docker",
|
|
21
|
+
"container",
|
|
22
|
+
"ssh"
|
|
23
|
+
],
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"dockerode": "^4.0.9",
|
|
26
|
+
"koishi": "4.18.10",
|
|
27
|
+
"ssh2": "^1.17.0"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"puppeteer": "^21.0.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/dockerode": "^3.3.47",
|
|
34
|
+
"@types/node": "^20.19.27",
|
|
35
|
+
"@types/ssh2": "^1.15.5",
|
|
36
|
+
"typescript": "^5.9.3"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# koishi-plugin-docker-control
|
|
2
|
+
|
|
3
|
+
Koishi 插件 - 通过 SSH 管理远程 Docker 容器
|
|
4
|
+
|
|
5
|
+
## 简介
|
|
6
|
+
|
|
7
|
+
通过 SSH 连接管理远程 Docker 容器,支持容器列表、启动、停止、重启、日志查看、命令执行等功能。
|
|
8
|
+
|
|
9
|
+
## 快速开始
|
|
10
|
+
|
|
11
|
+
### 1. 配置节点
|
|
12
|
+
|
|
13
|
+
在 Koishi 控制台配置 SSH 凭证和 Docker 节点。
|
|
14
|
+
|
|
15
|
+
### 2. 订阅容器通知
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
# 订阅指定节点的指定容器
|
|
19
|
+
docker.subscribe yun myapp
|
|
20
|
+
|
|
21
|
+
# 订阅指定节点的所有容器
|
|
22
|
+
docker.subscribe yun all
|
|
23
|
+
|
|
24
|
+
# 订阅所有节点的指定容器
|
|
25
|
+
docker.subscribe all myapp
|
|
26
|
+
|
|
27
|
+
# 订阅所有容器的所有事件
|
|
28
|
+
docker.subscribe all all
|
|
29
|
+
|
|
30
|
+
# 只监听启动和停止事件
|
|
31
|
+
docker.subscribe all all -e start,stop
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 3. 查看订阅
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
docker.subscriptions
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 4. 取消订阅
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
docker.unsubscribe <订阅ID>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 指令说明
|
|
47
|
+
|
|
48
|
+
### 基础指令
|
|
49
|
+
|
|
50
|
+
| 指令 | 说明 |
|
|
51
|
+
|------|------|
|
|
52
|
+
| `docker.ls` | 列出所有节点容器 |
|
|
53
|
+
| `docker.ls <selector>` | 列出指定节点容器 |
|
|
54
|
+
| `docker.ls -a` | 列出所有容器(含已停止) |
|
|
55
|
+
| `docker.ls -f image` | 图片格式输出 |
|
|
56
|
+
|
|
57
|
+
### 控制指令
|
|
58
|
+
|
|
59
|
+
| 指令 | 说明 |
|
|
60
|
+
|------|------|
|
|
61
|
+
| `docker.start <selector> <container>` | 启动容器 |
|
|
62
|
+
| `docker.stop <selector> <container>` | 停止容器 |
|
|
63
|
+
| `docker.restart <selector> <container>` | 重启容器 |
|
|
64
|
+
| `docker.inspect <selector> <container>` | 查看容器详情 |
|
|
65
|
+
|
|
66
|
+
### 日志与执行
|
|
67
|
+
|
|
68
|
+
| 指令 | 说明 |
|
|
69
|
+
|------|------|
|
|
70
|
+
| `docker.logs <container>` | 查看容器日志(自动搜索) |
|
|
71
|
+
| `docker.logs <container> <node>` | 查看指定节点容器日志 |
|
|
72
|
+
| `docker.logs <container> -n 100` | 查看最近 100 行日志 |
|
|
73
|
+
| `docker.exec <selector> <container> <cmd>` | 在容器内执行命令 |
|
|
74
|
+
|
|
75
|
+
### 订阅指令
|
|
76
|
+
|
|
77
|
+
| 指令 | 说明 |
|
|
78
|
+
|------|------|
|
|
79
|
+
| `docker.subscribe <node> <container>` | 订阅容器通知 |
|
|
80
|
+
| `docker.subscriptions` | 查看当前订阅 |
|
|
81
|
+
| `docker.unsubscribe <id>` | 取消订阅 |
|
|
82
|
+
|
|
83
|
+
## 参数说明
|
|
84
|
+
|
|
85
|
+
- **selector**: 节点选择器,支持节点 ID、节点名称或 `@标签`
|
|
86
|
+
- **container**: 容器名称或 ID(支持模糊匹配)
|
|
87
|
+
- **-n**: 日志行数限制
|
|
88
|
+
- **-a**: 显示所有容器(含已停止)
|
|
89
|
+
- **-f**: 输出格式(simple/detail/json/image)
|
|
90
|
+
- **-e**: 监听的事件类型(start/stop/restart/die)
|
|
91
|
+
|
|
92
|
+
## 配置项
|
|
93
|
+
|
|
94
|
+
- **debug**: 调试模式
|
|
95
|
+
- **imageOutput**: 图片格式输出
|
|
96
|
+
- **defaultLogLines**: 默认日志行数
|