@artenx/dshb 0.0.3 → 0.1.0
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/cordis.patch.yml +8 -49
- package/lib/auth/credentials.d.ts +30 -0
- package/lib/auth/credentials.js +121 -0
- package/lib/auth/credentials.js.map +1 -0
- package/lib/auth/decorate-webserver.d.ts +7 -0
- package/lib/auth/decorate-webserver.js +75 -0
- package/lib/auth/decorate-webserver.js.map +1 -0
- package/lib/auth/gate.d.ts +14 -0
- package/lib/auth/gate.js +45 -0
- package/lib/auth/gate.js.map +1 -0
- package/lib/auth/index.d.ts +8 -0
- package/lib/auth/index.js +51 -0
- package/lib/auth/index.js.map +1 -0
- package/lib/auth/login-page.d.ts +5 -0
- package/lib/auth/login-page.js +87 -0
- package/lib/auth/login-page.js.map +1 -0
- package/lib/auth/loopback-compat.d.ts +6 -0
- package/lib/auth/loopback-compat.js +94 -0
- package/lib/auth/loopback-compat.js.map +1 -0
- package/lib/auth/loopback.d.ts +7 -0
- package/lib/auth/loopback.js +24 -0
- package/lib/auth/loopback.js.map +1 -0
- package/lib/auth/ratelimit.d.ts +11 -0
- package/lib/auth/ratelimit.js +37 -0
- package/lib/auth/ratelimit.js.map +1 -0
- package/lib/auth/routes.d.ts +8 -0
- package/lib/auth/routes.js +224 -0
- package/lib/auth/routes.js.map +1 -0
- package/lib/auth/session.d.ts +11 -0
- package/lib/auth/session.js +52 -0
- package/lib/auth/session.js.map +1 -0
- package/lib/auth/startup.d.ts +15 -0
- package/lib/auth/startup.js +68 -0
- package/lib/auth/startup.js.map +1 -0
- package/lib/auth/webserver.d.ts +18 -0
- package/lib/auth/webserver.js +60 -0
- package/lib/auth/webserver.js.map +1 -0
- package/lib/client.js +2770 -0
- package/lib/client.js.map +1 -0
- package/lib/connection-sIX25pkS.d.ts +46 -0
- package/lib/core/audit.d.ts +16 -0
- package/lib/core/audit.js +38 -0
- package/lib/core/audit.js.map +1 -0
- package/lib/core/index.d.ts +8 -0
- package/lib/core/index.js +77 -0
- package/lib/core/index.js.map +1 -0
- package/lib/core/known-hosts.d.ts +23 -0
- package/lib/core/known-hosts.js +76 -0
- package/lib/core/known-hosts.js.map +1 -0
- package/lib/core/node-registry.d.ts +108 -0
- package/lib/core/node-registry.js +191 -0
- package/lib/core/node-registry.js.map +1 -0
- package/lib/core/routes.d.ts +9 -0
- package/lib/core/routes.js +404 -0
- package/lib/core/routes.js.map +1 -0
- package/lib/core/ssh-config.d.ts +23 -0
- package/lib/core/ssh-config.js +70 -0
- package/lib/core/ssh-config.js.map +1 -0
- package/lib/core/test.d.ts +43 -0
- package/lib/core/test.js +116 -0
- package/lib/core/test.js.map +1 -0
- package/lib/core/workspace-bindings.d.ts +28 -0
- package/lib/core/workspace-bindings.js +86 -0
- package/lib/core/workspace-bindings.js.map +1 -0
- package/lib/core/workspaces.d.ts +9 -0
- package/lib/core/workspaces.js +283 -0
- package/lib/core/workspaces.js.map +1 -0
- package/lib/exec-docker/daemon-runner.d.ts +21 -0
- package/lib/exec-docker/daemon-runner.js +326 -0
- package/lib/exec-docker/daemon-runner.js.map +1 -0
- package/lib/exec-docker/docker-backend.d.ts +48 -0
- package/lib/exec-docker/docker-backend.js +1 -0
- package/lib/exec-docker/docker-client.d.ts +46 -0
- package/lib/exec-docker/docker-client.js +302 -0
- package/lib/exec-docker/docker-client.js.map +1 -0
- package/lib/exec-docker/docker-routes.d.ts +6 -0
- package/lib/exec-docker/docker-routes.js +215 -0
- package/lib/exec-docker/docker-routes.js.map +1 -0
- package/lib/exec-docker/fs-provider.d.ts +50 -0
- package/lib/exec-docker/fs-provider.js +92 -0
- package/lib/exec-docker/fs-provider.js.map +1 -0
- package/lib/exec-docker/host-runner.d.ts +29 -0
- package/lib/exec-docker/host-runner.js +17 -0
- package/lib/exec-docker/host-runner.js.map +1 -0
- package/lib/exec-docker/index.d.ts +21 -0
- package/lib/exec-docker/index.js +137 -0
- package/lib/exec-docker/index.js.map +1 -0
- package/lib/exec-docker/process-provider.d.ts +20 -0
- package/lib/exec-docker/process-provider.js +75 -0
- package/lib/exec-docker/process-provider.js.map +1 -0
- package/lib/exec-docker/provision.d.ts +24 -0
- package/lib/exec-docker/provision.js +103 -0
- package/lib/exec-docker/provision.js.map +1 -0
- package/lib/exec-docker/remote-docker-cli.d.ts +52 -0
- package/lib/exec-docker/remote-docker-cli.js +155 -0
- package/lib/exec-docker/remote-docker-cli.js.map +1 -0
- package/lib/exec-docker/world.d.ts +37 -0
- package/lib/exec-docker/world.js +62 -0
- package/lib/exec-docker/world.js.map +1 -0
- package/lib/exec-ssh/connection-pool.d.ts +25 -0
- package/lib/exec-ssh/connection-pool.js +54 -0
- package/lib/exec-ssh/connection-pool.js.map +1 -0
- package/lib/exec-ssh/connection.d.ts +2 -0
- package/lib/exec-ssh/connection.js +125 -0
- package/lib/exec-ssh/connection.js.map +1 -0
- package/lib/exec-ssh/env-scrub.d.ts +7 -0
- package/lib/exec-ssh/env-scrub.js +40 -0
- package/lib/exec-ssh/env-scrub.js.map +1 -0
- package/lib/exec-ssh/executor.d.ts +46 -0
- package/lib/exec-ssh/executor.js +212 -0
- package/lib/exec-ssh/executor.js.map +1 -0
- package/lib/exec-ssh/fs-provider.d.ts +50 -0
- package/lib/exec-ssh/fs-provider.js +92 -0
- package/lib/exec-ssh/fs-provider.js.map +1 -0
- package/lib/exec-ssh/index.d.ts +16 -0
- package/lib/exec-ssh/index.js +30 -0
- package/lib/exec-ssh/index.js.map +1 -0
- package/lib/exec-ssh/process-provider.d.ts +20 -0
- package/lib/exec-ssh/process-provider.js +75 -0
- package/lib/exec-ssh/process-provider.js.map +1 -0
- package/lib/exec-ssh/runner.d.ts +13 -0
- package/lib/exec-ssh/runner.js +62 -0
- package/lib/exec-ssh/runner.js.map +1 -0
- package/lib/exec-ssh/world.d.ts +79 -0
- package/lib/exec-ssh/world.js +95 -0
- package/lib/exec-ssh/world.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/router/decorate-fs.d.ts +6 -0
- package/lib/router/decorate-fs.js +78 -0
- package/lib/router/decorate-fs.js.map +1 -0
- package/lib/router/decorate-shell.d.ts +6 -0
- package/lib/router/decorate-shell.js +35 -0
- package/lib/router/decorate-shell.js.map +1 -0
- package/lib/router/decorate-subprocess.d.ts +6 -0
- package/lib/router/decorate-subprocess.js +35 -0
- package/lib/router/decorate-subprocess.js.map +1 -0
- package/lib/router/index.d.ts +10 -0
- package/lib/router/index.js +21 -0
- package/lib/router/index.js.map +1 -0
- package/lib/router/resolve.d.ts +22 -0
- package/lib/router/resolve.js +45 -0
- package/lib/router/resolve.js.map +1 -0
- package/lib/router/router-fs.d.ts +25 -0
- package/lib/router/router-fs.js +64 -0
- package/lib/router/router-fs.js.map +1 -0
- package/lib/router/router-shell.d.ts +14 -0
- package/lib/router/router-shell.js +36 -0
- package/lib/router/router-shell.js.map +1 -0
- package/lib/router/router-subprocess.d.ts +13 -0
- package/lib/router/router-subprocess.js +33 -0
- package/lib/router/router-subprocess.js.map +1 -0
- package/lib/router/types.d.ts +2 -0
- package/lib/router/types.js +1 -0
- package/lib/types-C0TtEO7z.d.ts +67 -0
- package/lib/ui/decorate-picker.d.ts +6 -0
- package/lib/ui/decorate-picker.js +58 -0
- package/lib/ui/decorate-picker.js.map +1 -0
- package/lib/ui/index.d.ts +8 -0
- package/lib/ui/index.js +11 -0
- package/lib/ui/index.js.map +1 -0
- package/lib/ui/picker.d.ts +10 -0
- package/lib/ui/picker.js +58 -0
- package/lib/ui/picker.js.map +1 -0
- package/package.json +158 -9
- package/LICENSE +0 -21
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { parseDaemonHost } from "./daemon-runner.js";
|
|
2
|
+
import { request } from "node:http";
|
|
3
|
+
import { request as request$1 } from "node:https";
|
|
4
|
+
//#region src/exec-docker/docker-client.ts
|
|
5
|
+
const DAEMON = parseDaemonHost();
|
|
6
|
+
function requestRaw(opts, onResponse) {
|
|
7
|
+
const common = { ...opts };
|
|
8
|
+
if (DAEMON.socketPath) return request({
|
|
9
|
+
...common,
|
|
10
|
+
socketPath: DAEMON.socketPath
|
|
11
|
+
}, onResponse);
|
|
12
|
+
return (DAEMON.tls ? request$1 : request)({
|
|
13
|
+
...common,
|
|
14
|
+
hostname: DAEMON.host,
|
|
15
|
+
port: DAEMON.port
|
|
16
|
+
}, onResponse);
|
|
17
|
+
}
|
|
18
|
+
function dockerRequest(method, path, body) {
|
|
19
|
+
const headers = body ? { "content-type": "application/json" } : {};
|
|
20
|
+
if (DAEMON.socketPath) return new Promise((resolve, reject) => {
|
|
21
|
+
const req = request({
|
|
22
|
+
method,
|
|
23
|
+
path,
|
|
24
|
+
socketPath: DAEMON.socketPath,
|
|
25
|
+
headers
|
|
26
|
+
}, (res) => {
|
|
27
|
+
const chunks = [];
|
|
28
|
+
res.on("data", (c) => chunks.push(c));
|
|
29
|
+
res.on("end", () => {
|
|
30
|
+
resolve({
|
|
31
|
+
statusCode: res.statusCode ?? 0,
|
|
32
|
+
headers: res.headers,
|
|
33
|
+
body: Buffer.concat(chunks)
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
res.on("error", reject);
|
|
37
|
+
});
|
|
38
|
+
req.on("error", reject);
|
|
39
|
+
if (body) req.write(JSON.stringify(body));
|
|
40
|
+
req.end();
|
|
41
|
+
});
|
|
42
|
+
const mod = DAEMON.tls ? request$1 : request;
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
const req = mod({
|
|
45
|
+
method,
|
|
46
|
+
path,
|
|
47
|
+
hostname: DAEMON.host,
|
|
48
|
+
port: DAEMON.port,
|
|
49
|
+
headers
|
|
50
|
+
}, (res) => {
|
|
51
|
+
const chunks = [];
|
|
52
|
+
res.on("data", (c) => chunks.push(c));
|
|
53
|
+
res.on("end", () => {
|
|
54
|
+
resolve({
|
|
55
|
+
statusCode: res.statusCode ?? 0,
|
|
56
|
+
headers: res.headers,
|
|
57
|
+
body: Buffer.concat(chunks)
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
res.on("error", reject);
|
|
61
|
+
});
|
|
62
|
+
req.on("error", reject);
|
|
63
|
+
if (body) req.write(JSON.stringify(body));
|
|
64
|
+
req.end();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function demux(data) {
|
|
68
|
+
const stdout = [];
|
|
69
|
+
const stderr = [];
|
|
70
|
+
let pos = 0;
|
|
71
|
+
while (pos + 8 <= data.length) {
|
|
72
|
+
const streamType = data[pos];
|
|
73
|
+
const length = data.readUInt32BE(pos + 4);
|
|
74
|
+
pos += 8;
|
|
75
|
+
if (pos + length > data.length) break;
|
|
76
|
+
const payload = data.subarray(pos, pos + length);
|
|
77
|
+
pos += length;
|
|
78
|
+
if (streamType === 1) stdout.push(payload);
|
|
79
|
+
else if (streamType === 2) stderr.push(payload);
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
stdout,
|
|
83
|
+
stderr
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function shellQuote(s) {
|
|
87
|
+
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
88
|
+
}
|
|
89
|
+
var DockerClient = class {
|
|
90
|
+
containerId;
|
|
91
|
+
constructor(containerId) {
|
|
92
|
+
this.containerId = containerId;
|
|
93
|
+
}
|
|
94
|
+
async ping() {
|
|
95
|
+
try {
|
|
96
|
+
return (await dockerRequest("GET", "/_ping")).statusCode === 200;
|
|
97
|
+
} catch {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async inspect() {
|
|
102
|
+
const res = await dockerRequest("GET", `/containers/${this.containerId}/json`);
|
|
103
|
+
if (res.statusCode !== 200) return void 0;
|
|
104
|
+
const data = JSON.parse(res.body.toString("utf8"));
|
|
105
|
+
return {
|
|
106
|
+
running: data.State?.Running ?? false,
|
|
107
|
+
name: data.Name ?? this.containerId
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
async exec(argv, cwd, env = {}, stdinData) {
|
|
111
|
+
const createRes = await dockerRequest("POST", `/containers/${this.containerId}/exec`, {
|
|
112
|
+
AttachStdout: true,
|
|
113
|
+
AttachStderr: true,
|
|
114
|
+
AttachStdin: stdinData !== void 0,
|
|
115
|
+
Tty: false,
|
|
116
|
+
WorkingDir: cwd,
|
|
117
|
+
Env: Object.entries(env).map(([k, v]) => `${k}=${v}`),
|
|
118
|
+
Cmd: argv
|
|
119
|
+
});
|
|
120
|
+
if (createRes.statusCode !== 201) return {
|
|
121
|
+
code: 126,
|
|
122
|
+
stdout: "",
|
|
123
|
+
stderr: `docker exec create failed: ${createRes.body.toString("utf8")}`
|
|
124
|
+
};
|
|
125
|
+
const execId = JSON.parse(createRes.body.toString("utf8")).Id;
|
|
126
|
+
if (!execId) return {
|
|
127
|
+
code: 126,
|
|
128
|
+
stdout: "",
|
|
129
|
+
stderr: "docker exec: no Id returned"
|
|
130
|
+
};
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
132
|
+
const req = requestRaw({
|
|
133
|
+
method: "POST",
|
|
134
|
+
path: `/exec/${execId}/start`,
|
|
135
|
+
headers: {
|
|
136
|
+
"content-type": "application/json",
|
|
137
|
+
connection: "upgrade"
|
|
138
|
+
}
|
|
139
|
+
}, (res) => {
|
|
140
|
+
const chunks = [];
|
|
141
|
+
res.on("data", (c) => chunks.push(c));
|
|
142
|
+
res.on("end", () => {
|
|
143
|
+
const demuxed = demux(Buffer.concat(chunks));
|
|
144
|
+
const inspectReq = requestRaw({
|
|
145
|
+
method: "GET",
|
|
146
|
+
path: `/exec/${execId}/json`,
|
|
147
|
+
headers: {}
|
|
148
|
+
}, (inspectRes) => {
|
|
149
|
+
const ichunks = [];
|
|
150
|
+
inspectRes.on("data", (c) => ichunks.push(c));
|
|
151
|
+
inspectRes.on("end", () => {
|
|
152
|
+
let code = 0;
|
|
153
|
+
try {
|
|
154
|
+
code = JSON.parse(Buffer.concat(ichunks).toString("utf8")).ExitCode ?? 0;
|
|
155
|
+
} catch {}
|
|
156
|
+
resolve({
|
|
157
|
+
code,
|
|
158
|
+
stdout: Buffer.concat(demuxed.stdout).toString("utf8"),
|
|
159
|
+
stderr: Buffer.concat(demuxed.stderr).toString("utf8")
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
inspectRes.on("error", () => resolve({
|
|
163
|
+
code: 0,
|
|
164
|
+
stdout: Buffer.concat(demuxed.stdout).toString("utf8"),
|
|
165
|
+
stderr: Buffer.concat(demuxed.stderr).toString("utf8")
|
|
166
|
+
}));
|
|
167
|
+
});
|
|
168
|
+
inspectReq.on("error", () => resolve({
|
|
169
|
+
code: 0,
|
|
170
|
+
stdout: Buffer.concat(demuxed.stdout).toString("utf8"),
|
|
171
|
+
stderr: Buffer.concat(demuxed.stderr).toString("utf8")
|
|
172
|
+
}));
|
|
173
|
+
inspectReq.end();
|
|
174
|
+
});
|
|
175
|
+
res.on("error", reject);
|
|
176
|
+
});
|
|
177
|
+
req.on("error", reject);
|
|
178
|
+
req.write(JSON.stringify({
|
|
179
|
+
Detach: false,
|
|
180
|
+
Tty: false
|
|
181
|
+
}));
|
|
182
|
+
if (stdinData) req.write(stdinData);
|
|
183
|
+
req.end();
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
async execShell(command, cwd) {
|
|
187
|
+
return this.exec([
|
|
188
|
+
"bash",
|
|
189
|
+
"-c",
|
|
190
|
+
command
|
|
191
|
+
], cwd);
|
|
192
|
+
}
|
|
193
|
+
async readFile(path) {
|
|
194
|
+
const result = await this.exec(["cat", path], "/");
|
|
195
|
+
return Buffer.from(result.stdout, "utf8");
|
|
196
|
+
}
|
|
197
|
+
async writeFile(path, content) {
|
|
198
|
+
const b64 = (Buffer.isBuffer(content) ? content : Buffer.from(content, "utf8")).toString("base64");
|
|
199
|
+
await this.execShell(`printf '%s' '${b64}' | base64 -d > ${shellQuote(path)}`, "/");
|
|
200
|
+
}
|
|
201
|
+
async listDir(path) {
|
|
202
|
+
return (await this.execShell(`ls -1pa --time-style=+%s ${shellQuote(path)} 2>/dev/null`, "/")).stdout.split("\n").filter((line) => line.trim()).map((line) => {
|
|
203
|
+
const name = line.replace(/[/@*]$/, "").trim();
|
|
204
|
+
if (!name) return null;
|
|
205
|
+
const isDir = line.endsWith("/");
|
|
206
|
+
const isSymlink = line.endsWith("@");
|
|
207
|
+
return {
|
|
208
|
+
name,
|
|
209
|
+
isDir,
|
|
210
|
+
isFile: !isDir && !isSymlink,
|
|
211
|
+
isSymlink,
|
|
212
|
+
size: 0,
|
|
213
|
+
mtime: 0
|
|
214
|
+
};
|
|
215
|
+
}).filter((e) => e !== null);
|
|
216
|
+
}
|
|
217
|
+
async stat(path) {
|
|
218
|
+
const line = (await this.execShell(`stat -c '%s %Y %F' ${shellQuote(path)} 2>/dev/null`, "/")).stdout.trim();
|
|
219
|
+
if (!line) return void 0;
|
|
220
|
+
const parts = line.split(/\s+/);
|
|
221
|
+
if (parts.length < 3) return void 0;
|
|
222
|
+
const size = Number(parts[0]);
|
|
223
|
+
const mtime = Number(parts[1]) * 1e3;
|
|
224
|
+
const ftype = parts.slice(2).join(" ");
|
|
225
|
+
return {
|
|
226
|
+
size,
|
|
227
|
+
mtime,
|
|
228
|
+
isDirectory: ftype.includes("directory"),
|
|
229
|
+
isFile: ftype.includes("regular file") || ftype.includes("regular empty file")
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
async mkdir(path) {
|
|
233
|
+
await this.exec([
|
|
234
|
+
"mkdir",
|
|
235
|
+
"-p",
|
|
236
|
+
path
|
|
237
|
+
], "/");
|
|
238
|
+
}
|
|
239
|
+
async remove(path) {
|
|
240
|
+
await this.exec([
|
|
241
|
+
"rm",
|
|
242
|
+
"-f",
|
|
243
|
+
path
|
|
244
|
+
], "/");
|
|
245
|
+
}
|
|
246
|
+
async rename(src, dest) {
|
|
247
|
+
await this.exec([
|
|
248
|
+
"mv",
|
|
249
|
+
src,
|
|
250
|
+
dest
|
|
251
|
+
], "/");
|
|
252
|
+
}
|
|
253
|
+
async pty(argv, cwd, cols, rows) {
|
|
254
|
+
const createRes = await dockerRequest("POST", `/containers/${this.containerId}/exec`, {
|
|
255
|
+
AttachStdout: true,
|
|
256
|
+
AttachStderr: true,
|
|
257
|
+
AttachStdin: true,
|
|
258
|
+
Tty: true,
|
|
259
|
+
WorkingDir: cwd,
|
|
260
|
+
Cmd: argv
|
|
261
|
+
});
|
|
262
|
+
if (createRes.statusCode !== 201) throw new Error("docker exec create failed");
|
|
263
|
+
const execId = JSON.parse(createRes.body.toString("utf8")).Id;
|
|
264
|
+
return new Promise((resolve, reject) => {
|
|
265
|
+
const req = requestRaw({
|
|
266
|
+
method: "POST",
|
|
267
|
+
path: `/exec/${execId}/start`,
|
|
268
|
+
headers: {
|
|
269
|
+
"content-type": "application/json",
|
|
270
|
+
connection: "upgrade"
|
|
271
|
+
}
|
|
272
|
+
}, (res) => {
|
|
273
|
+
resolve({
|
|
274
|
+
stream: res,
|
|
275
|
+
resize: (c, r) => {
|
|
276
|
+
requestRaw({
|
|
277
|
+
method: "POST",
|
|
278
|
+
path: `/exec/${execId}/resize?h=${r}&w=${c}`,
|
|
279
|
+
headers: {}
|
|
280
|
+
}, () => {}).end();
|
|
281
|
+
},
|
|
282
|
+
kill: () => {
|
|
283
|
+
res.destroy();
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
req.on("error", reject);
|
|
288
|
+
req.write(JSON.stringify({
|
|
289
|
+
Detach: false,
|
|
290
|
+
Tty: true
|
|
291
|
+
}));
|
|
292
|
+
req.end();
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
async ensureRg() {
|
|
296
|
+
if ((await this.execShell("command -v rg || echo __missing__", "/")).stdout.includes("__missing__")) await this.execShell("apk add --no-cache ripgrep 2>/dev/null || apt-get install -y ripgrep 2>/dev/null || true", "/");
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
//#endregion
|
|
300
|
+
export { DockerClient };
|
|
301
|
+
|
|
302
|
+
//# sourceMappingURL=docker-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker-client.js","names":["httpRequest","httpsRequest"],"sources":["../../src/exec-docker/docker-client.ts"],"sourcesContent":["import type { IncomingMessage, ClientRequest } from 'node:http'\nimport { request as httpRequest } from 'node:http'\nimport { request as httpsRequest } from 'node:https'\nimport type { DockerBackend } from './docker-backend.js'\nimport { parseDaemonHost } from './daemon-runner.js'\n\nconst DAEMON = parseDaemonHost()\n\ninterface ExecResult {\n code: number\n stdout: string\n stderr: string\n}\n\ninterface Demuxed {\n stdout: Buffer[]\n stderr: Buffer[]\n}\n\nfunction requestRaw(\n opts: { method: string; path: string; headers: Record<string, string> },\n onResponse: (res: IncomingMessage) => void,\n): ClientRequest {\n const common = { ...opts }\n if (DAEMON.socketPath) return httpRequest({ ...common, socketPath: DAEMON.socketPath } as never, onResponse)\n const mod = DAEMON.tls ? httpsRequest : httpRequest\n return mod({ ...common, hostname: DAEMON.host, port: DAEMON.port } as never, onResponse)\n}\n\nfunction dockerRequest(method: string, path: string, body?: unknown): Promise<{ statusCode: number; headers: Record<string, string>; body: Buffer }> {\n const headers = body ? { 'content-type': 'application/json' } : {}\n if (DAEMON.socketPath) {\n return new Promise((resolve, reject) => {\n const req = httpRequest({ method, path, socketPath: DAEMON.socketPath as string, headers }, (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () => {\n resolve({\n statusCode: res.statusCode ?? 0,\n headers: res.headers as Record<string, string>,\n body: Buffer.concat(chunks),\n })\n })\n res.on('error', reject)\n })\n req.on('error', reject)\n if (body) req.write(JSON.stringify(body))\n req.end()\n })\n }\n const mod = DAEMON.tls ? httpsRequest : httpRequest\n return new Promise((resolve, reject) => {\n const req = mod({ method, path, hostname: DAEMON.host, port: DAEMON.port, headers }, (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () => {\n resolve({\n statusCode: res.statusCode ?? 0,\n headers: res.headers as Record<string, string>,\n body: Buffer.concat(chunks),\n })\n })\n res.on('error', reject)\n })\n req.on('error', reject)\n if (body) req.write(JSON.stringify(body))\n req.end()\n })\n}\n\nfunction demux(data: Buffer): Demuxed {\n const stdout: Buffer[] = []\n const stderr: Buffer[] = []\n let pos = 0\n while (pos + 8 <= data.length) {\n const streamType = data[pos]\n const length = data.readUInt32BE(pos + 4)\n pos += 8\n if (pos + length > data.length) break\n const payload = data.subarray(pos, pos + length)\n pos += length\n if (streamType === 1) stdout.push(payload)\n else if (streamType === 2) stderr.push(payload)\n }\n return { stdout, stderr }\n}\n\nfunction shellQuote(s: string): string {\n return `'${s.replace(/'/g, \"'\\\\''\")}'`\n}\n\nexport class DockerClient implements DockerBackend {\n private readonly containerId: string\n\n constructor(containerId: string) {\n this.containerId = containerId\n }\n\n async ping(): Promise<boolean> {\n try {\n const res = await dockerRequest('GET', '/_ping')\n return res.statusCode === 200\n } catch {\n return false\n }\n }\n\n async inspect(): Promise<{ running: boolean; name: string } | undefined> {\n const res = await dockerRequest('GET', `/containers/${this.containerId}/json`)\n if (res.statusCode !== 200) return undefined\n const data = JSON.parse(res.body.toString('utf8'))\n return { running: data.State?.Running ?? false, name: data.Name ?? this.containerId }\n }\n\n async exec(argv: string[], cwd: string, env: Record<string, string> = {}, stdinData?: Buffer): Promise<ExecResult> {\n const createRes = await dockerRequest('POST', `/containers/${this.containerId}/exec`, {\n AttachStdout: true,\n AttachStderr: true,\n AttachStdin: stdinData !== undefined,\n Tty: false,\n WorkingDir: cwd,\n Env: Object.entries(env).map(([k, v]) => `${k}=${v}`),\n Cmd: argv,\n })\n if (createRes.statusCode !== 201) {\n const msg = createRes.body.toString('utf8')\n return { code: 126, stdout: '', stderr: `docker exec create failed: ${msg}` }\n }\n const execId = JSON.parse(createRes.body.toString('utf8')).Id\n if (!execId) return { code: 126, stdout: '', stderr: 'docker exec: no Id returned' }\n\n return new Promise<ExecResult>((resolve, reject) => {\n const req = requestRaw(\n {\n method: 'POST',\n path: `/exec/${execId}/start`,\n headers: { 'content-type': 'application/json', connection: 'upgrade' },\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () => {\n const raw = Buffer.concat(chunks)\n const demuxed = demux(raw)\n const inspectReq = requestRaw(\n { method: 'GET', path: `/exec/${execId}/json`, headers: {} },\n (inspectRes) => {\n const ichunks: Buffer[] = []\n inspectRes.on('data', (c: Buffer) => ichunks.push(c))\n inspectRes.on('end', () => {\n let code = 0\n try {\n const info = JSON.parse(Buffer.concat(ichunks).toString('utf8'))\n code = info.ExitCode ?? 0\n } catch {}\n resolve({\n code,\n stdout: Buffer.concat(demuxed.stdout).toString('utf8'),\n stderr: Buffer.concat(demuxed.stderr).toString('utf8'),\n })\n })\n inspectRes.on('error', () => resolve({ code: 0, stdout: Buffer.concat(demuxed.stdout).toString('utf8'), stderr: Buffer.concat(demuxed.stderr).toString('utf8') }))\n },\n )\n inspectReq.on('error', () => resolve({ code: 0, stdout: Buffer.concat(demuxed.stdout).toString('utf8'), stderr: Buffer.concat(demuxed.stderr).toString('utf8') }))\n inspectReq.end()\n })\n res.on('error', reject)\n },\n )\n req.on('error', reject)\n req.write(JSON.stringify({ Detach: false, Tty: false }))\n if (stdinData) req.write(stdinData)\n req.end()\n })\n }\n\n async execShell(command: string, cwd: string): Promise<ExecResult> {\n return this.exec(['bash', '-c', command], cwd)\n }\n\n async readFile(path: string): Promise<Buffer> {\n const result = await this.exec(['cat', path], '/')\n return Buffer.from(result.stdout, 'utf8')\n }\n\n async writeFile(path: string, content: Buffer | string): Promise<void> {\n const data = Buffer.isBuffer(content) ? content : Buffer.from(content, 'utf8')\n const b64 = data.toString('base64')\n await this.execShell(`printf '%s' '${b64}' | base64 -d > ${shellQuote(path)}`, '/')\n }\n\n async listDir(path: string): Promise<Array<{ name: string; isDir: boolean; isFile: boolean; isSymlink: boolean; size: number; mtime: number }>> {\n const result = await this.execShell(`ls -1pa --time-style=+%s ${shellQuote(path)} 2>/dev/null`, '/')\n return result.stdout\n .split('\\n')\n .filter((line) => line.trim())\n .map((line) => {\n const name = line.replace(/[/@*]$/, '').trim()\n if (!name) return null\n const isDir = line.endsWith('/')\n const isSymlink = line.endsWith('@')\n return {\n name,\n isDir,\n isFile: !isDir && !isSymlink,\n isSymlink,\n size: 0,\n mtime: 0,\n }\n })\n .filter((e): e is NonNullable<typeof e> => e !== null)\n }\n\n async stat(path: string): Promise<{ size: number; mtime: number; isDirectory: boolean; isFile: boolean } | undefined> {\n const result = await this.execShell(`stat -c '%s %Y %F' ${shellQuote(path)} 2>/dev/null`, '/')\n const line = result.stdout.trim()\n if (!line) return undefined\n const parts = line.split(/\\s+/)\n if (parts.length < 3) return undefined\n const size = Number(parts[0])\n const mtime = Number(parts[1]) * 1000\n const ftype = parts.slice(2).join(' ')\n return {\n size,\n mtime,\n isDirectory: ftype.includes('directory'),\n isFile: ftype.includes('regular file') || ftype.includes('regular empty file'),\n }\n }\n\n async mkdir(path: string): Promise<void> {\n await this.exec(['mkdir', '-p', path], '/')\n }\n\n async remove(path: string): Promise<void> {\n await this.exec(['rm', '-f', path], '/')\n }\n\n async rename(src: string, dest: string): Promise<void> {\n await this.exec(['mv', src, dest], '/')\n }\n\n async pty(argv: string[], cwd: string, cols: number, rows: number): Promise<{ stream: NodeJS.ReadWriteStream; resize: (c: number, r: number) => void; kill: () => void }> {\n const createRes = await dockerRequest('POST', `/containers/${this.containerId}/exec`, {\n AttachStdout: true,\n AttachStderr: true,\n AttachStdin: true,\n Tty: true,\n WorkingDir: cwd,\n Cmd: argv,\n })\n if (createRes.statusCode !== 201) throw new Error('docker exec create failed')\n const execId = JSON.parse(createRes.body.toString('utf8')).Id\n\n return new Promise((resolve, reject) => {\n const req = requestRaw(\n {\n method: 'POST',\n path: `/exec/${execId}/start`,\n headers: { 'content-type': 'application/json', connection: 'upgrade' },\n },\n (res) => {\n resolve({\n stream: res as unknown as NodeJS.ReadWriteStream,\n resize: (c: number, r: number) => {\n const r2 = requestRaw({ method: 'POST', path: `/exec/${execId}/resize?h=${r}&w=${c}`, headers: {} }, () => {})\n r2.end()\n },\n kill: () => {\n res.destroy()\n },\n })\n },\n )\n req.on('error', reject)\n req.write(JSON.stringify({ Detach: false, Tty: true }))\n req.end()\n })\n }\n\n async ensureRg(): Promise<void> {\n const result = await this.execShell('command -v rg || echo __missing__', '/')\n if (result.stdout.includes('__missing__')) {\n await this.execShell('apk add --no-cache ripgrep 2>/dev/null || apt-get install -y ripgrep 2>/dev/null || true', '/')\n }\n }\n}\n"],"mappings":";;;;AAMA,MAAM,SAAS,gBAAgB;AAa/B,SAAS,WACP,MACA,YACe;CACf,MAAM,SAAS,EAAE,GAAG,KAAK;CACzB,IAAI,OAAO,YAAY,OAAOA,QAAY;EAAE,GAAG;EAAQ,YAAY,OAAO;CAAW,GAAY,UAAU;CAE3G,QADY,OAAO,MAAMC,YAAeD,QAAAA,CAC7B;EAAE,GAAG;EAAQ,UAAU,OAAO;EAAM,MAAM,OAAO;CAAK,GAAY,UAAU;AACzF;AAEA,SAAS,cAAc,QAAgB,MAAc,MAAgG;CACnJ,MAAM,UAAU,OAAO,EAAE,gBAAgB,mBAAmB,IAAI,CAAC;CACjE,IAAI,OAAO,YACT,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,MAAMA,QAAY;GAAE;GAAQ;GAAM,YAAY,OAAO;GAAsB;EAAQ,IAAI,QAAQ;GACnG,MAAM,SAAmB,CAAC;GAC1B,IAAI,GAAG,SAAS,MAAc,OAAO,KAAK,CAAC,CAAC;GAC5C,IAAI,GAAG,aAAa;IAClB,QAAQ;KACN,YAAY,IAAI,cAAc;KAC9B,SAAS,IAAI;KACb,MAAM,OAAO,OAAO,MAAM;IAC5B,CAAC;GACH,CAAC;GACD,IAAI,GAAG,SAAS,MAAM;EACxB,CAAC;EACD,IAAI,GAAG,SAAS,MAAM;EACtB,IAAI,MAAM,IAAI,MAAM,KAAK,UAAU,IAAI,CAAC;EACxC,IAAI,IAAI;CACV,CAAC;CAEH,MAAM,MAAM,OAAO,MAAMC,YAAeD;CACxC,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,MAAM,IAAI;GAAE;GAAQ;GAAM,UAAU,OAAO;GAAM,MAAM,OAAO;GAAM;EAAQ,IAAI,QAAQ;GAC5F,MAAM,SAAmB,CAAC;GAC1B,IAAI,GAAG,SAAS,MAAc,OAAO,KAAK,CAAC,CAAC;GAC5C,IAAI,GAAG,aAAa;IAClB,QAAQ;KACN,YAAY,IAAI,cAAc;KAC9B,SAAS,IAAI;KACb,MAAM,OAAO,OAAO,MAAM;IAC5B,CAAC;GACH,CAAC;GACD,IAAI,GAAG,SAAS,MAAM;EACxB,CAAC;EACD,IAAI,GAAG,SAAS,MAAM;EACtB,IAAI,MAAM,IAAI,MAAM,KAAK,UAAU,IAAI,CAAC;EACxC,IAAI,IAAI;CACV,CAAC;AACH;AAEA,SAAS,MAAM,MAAuB;CACpC,MAAM,SAAmB,CAAC;CAC1B,MAAM,SAAmB,CAAC;CAC1B,IAAI,MAAM;CACV,OAAO,MAAM,KAAK,KAAK,QAAQ;EAC7B,MAAM,aAAa,KAAK;EACxB,MAAM,SAAS,KAAK,aAAa,MAAM,CAAC;EACxC,OAAO;EACP,IAAI,MAAM,SAAS,KAAK,QAAQ;EAChC,MAAM,UAAU,KAAK,SAAS,KAAK,MAAM,MAAM;EAC/C,OAAO;EACP,IAAI,eAAe,GAAG,OAAO,KAAK,OAAO;OACpC,IAAI,eAAe,GAAG,OAAO,KAAK,OAAO;CAChD;CACA,OAAO;EAAE;EAAQ;CAAO;AAC1B;AAEA,SAAS,WAAW,GAAmB;CACrC,OAAO,IAAI,EAAE,QAAQ,MAAM,OAAO,EAAE;AACtC;AAEA,IAAa,eAAb,MAAmD;CACjD;CAEA,YAAY,aAAqB;EAC/B,KAAK,cAAc;CACrB;CAEA,MAAM,OAAyB;EAC7B,IAAI;GAEF,QAAO,MADW,cAAc,OAAO,QAAQ,EAAA,CACpC,eAAe;EAC5B,QAAQ;GACN,OAAO;EACT;CACF;CAEA,MAAM,UAAmE;EACvE,MAAM,MAAM,MAAM,cAAc,OAAO,eAAe,KAAK,YAAY,MAAM;EAC7E,IAAI,IAAI,eAAe,KAAK,OAAO,KAAA;EACnC,MAAM,OAAO,KAAK,MAAM,IAAI,KAAK,SAAS,MAAM,CAAC;EACjD,OAAO;GAAE,SAAS,KAAK,OAAO,WAAW;GAAO,MAAM,KAAK,QAAQ,KAAK;EAAY;CACtF;CAEA,MAAM,KAAK,MAAgB,KAAa,MAA8B,CAAC,GAAG,WAAyC;EACjH,MAAM,YAAY,MAAM,cAAc,QAAQ,eAAe,KAAK,YAAY,QAAQ;GACpF,cAAc;GACd,cAAc;GACd,aAAa,cAAc,KAAA;GAC3B,KAAK;GACL,YAAY;GACZ,KAAK,OAAO,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,GAAG,GAAG;GACpD,KAAK;EACP,CAAC;EACD,IAAI,UAAU,eAAe,KAE3B,OAAO;GAAE,MAAM;GAAK,QAAQ;GAAI,QAAQ,8BAD5B,UAAU,KAAK,SAAS,MACoC;EAAI;EAE9E,MAAM,SAAS,KAAK,MAAM,UAAU,KAAK,SAAS,MAAM,CAAC,CAAC,CAAC;EAC3D,IAAI,CAAC,QAAQ,OAAO;GAAE,MAAM;GAAK,QAAQ;GAAI,QAAQ;EAA8B;EAEnF,OAAO,IAAI,SAAqB,SAAS,WAAW;GAClD,MAAM,MAAM,WACV;IACE,QAAQ;IACR,MAAM,SAAS,OAAO;IACtB,SAAS;KAAE,gBAAgB;KAAoB,YAAY;IAAU;GACvE,IACC,QAAQ;IACP,MAAM,SAAmB,CAAC;IAC1B,IAAI,GAAG,SAAS,MAAc,OAAO,KAAK,CAAC,CAAC;IAC5C,IAAI,GAAG,aAAa;KAElB,MAAM,UAAU,MADJ,OAAO,OAAO,MACF,CAAC;KACzB,MAAM,aAAa,WACjB;MAAE,QAAQ;MAAO,MAAM,SAAS,OAAO;MAAQ,SAAS,CAAC;KAAE,IAC1D,eAAe;MACd,MAAM,UAAoB,CAAC;MAC3B,WAAW,GAAG,SAAS,MAAc,QAAQ,KAAK,CAAC,CAAC;MACpD,WAAW,GAAG,aAAa;OACzB,IAAI,OAAO;OACX,IAAI;QAEF,OADa,KAAK,MAAM,OAAO,OAAO,OAAO,CAAC,CAAC,SAAS,MAAM,CACpD,CAAC,CAAC,YAAY;OAC1B,QAAQ,CAAC;OACT,QAAQ;QACN;QACA,QAAQ,OAAO,OAAO,QAAQ,MAAM,CAAC,CAAC,SAAS,MAAM;QACrD,QAAQ,OAAO,OAAO,QAAQ,MAAM,CAAC,CAAC,SAAS,MAAM;OACvD,CAAC;MACH,CAAC;MACD,WAAW,GAAG,eAAe,QAAQ;OAAE,MAAM;OAAG,QAAQ,OAAO,OAAO,QAAQ,MAAM,CAAC,CAAC,SAAS,MAAM;OAAG,QAAQ,OAAO,OAAO,QAAQ,MAAM,CAAC,CAAC,SAAS,MAAM;MAAE,CAAC,CAAC;KACnK,CACF;KACA,WAAW,GAAG,eAAe,QAAQ;MAAE,MAAM;MAAG,QAAQ,OAAO,OAAO,QAAQ,MAAM,CAAC,CAAC,SAAS,MAAM;MAAG,QAAQ,OAAO,OAAO,QAAQ,MAAM,CAAC,CAAC,SAAS,MAAM;KAAE,CAAC,CAAC;KACjK,WAAW,IAAI;IACjB,CAAC;IACD,IAAI,GAAG,SAAS,MAAM;GACxB,CACF;GACA,IAAI,GAAG,SAAS,MAAM;GACtB,IAAI,MAAM,KAAK,UAAU;IAAE,QAAQ;IAAO,KAAK;GAAM,CAAC,CAAC;GACvD,IAAI,WAAW,IAAI,MAAM,SAAS;GAClC,IAAI,IAAI;EACV,CAAC;CACH;CAEA,MAAM,UAAU,SAAiB,KAAkC;EACjE,OAAO,KAAK,KAAK;GAAC;GAAQ;GAAM;EAAO,GAAG,GAAG;CAC/C;CAEA,MAAM,SAAS,MAA+B;EAC5C,MAAM,SAAS,MAAM,KAAK,KAAK,CAAC,OAAO,IAAI,GAAG,GAAG;EACjD,OAAO,OAAO,KAAK,OAAO,QAAQ,MAAM;CAC1C;CAEA,MAAM,UAAU,MAAc,SAAyC;EAErE,MAAM,OADO,OAAO,SAAS,OAAO,IAAI,UAAU,OAAO,KAAK,SAAS,MAAM,EAAA,CAC5D,SAAS,QAAQ;EAClC,MAAM,KAAK,UAAU,gBAAgB,IAAI,kBAAkB,WAAW,IAAI,KAAK,GAAG;CACpF;CAEA,MAAM,QAAQ,MAAkI;EAE9I,QAAO,MADc,KAAK,UAAU,4BAA4B,WAAW,IAAI,EAAE,eAAe,GAAG,EAAA,CACrF,OACX,MAAM,IAAI,CAAC,CACX,QAAQ,SAAS,KAAK,KAAK,CAAC,CAAC,CAC7B,KAAK,SAAS;GACb,MAAM,OAAO,KAAK,QAAQ,UAAU,EAAE,CAAC,CAAC,KAAK;GAC7C,IAAI,CAAC,MAAM,OAAO;GAClB,MAAM,QAAQ,KAAK,SAAS,GAAG;GAC/B,MAAM,YAAY,KAAK,SAAS,GAAG;GACnC,OAAO;IACL;IACA;IACA,QAAQ,CAAC,SAAS,CAAC;IACnB;IACA,MAAM;IACN,OAAO;GACT;EACF,CAAC,CAAC,CACD,QAAQ,MAAkC,MAAM,IAAI;CACzD;CAEA,MAAM,KAAK,MAA2G;EAEpH,MAAM,QAAO,MADQ,KAAK,UAAU,sBAAsB,WAAW,IAAI,EAAE,eAAe,GAAG,EAAA,CACzE,OAAO,KAAK;EAChC,IAAI,CAAC,MAAM,OAAO,KAAA;EAClB,MAAM,QAAQ,KAAK,MAAM,KAAK;EAC9B,IAAI,MAAM,SAAS,GAAG,OAAO,KAAA;EAC7B,MAAM,OAAO,OAAO,MAAM,EAAE;EAC5B,MAAM,QAAQ,OAAO,MAAM,EAAE,IAAI;EACjC,MAAM,QAAQ,MAAM,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG;EACrC,OAAO;GACL;GACA;GACA,aAAa,MAAM,SAAS,WAAW;GACvC,QAAQ,MAAM,SAAS,cAAc,KAAK,MAAM,SAAS,oBAAoB;EAC/E;CACF;CAEA,MAAM,MAAM,MAA6B;EACvC,MAAM,KAAK,KAAK;GAAC;GAAS;GAAM;EAAI,GAAG,GAAG;CAC5C;CAEA,MAAM,OAAO,MAA6B;EACxC,MAAM,KAAK,KAAK;GAAC;GAAM;GAAM;EAAI,GAAG,GAAG;CACzC;CAEA,MAAM,OAAO,KAAa,MAA6B;EACrD,MAAM,KAAK,KAAK;GAAC;GAAM;GAAK;EAAI,GAAG,GAAG;CACxC;CAEA,MAAM,IAAI,MAAgB,KAAa,MAAc,MAAqH;EACxK,MAAM,YAAY,MAAM,cAAc,QAAQ,eAAe,KAAK,YAAY,QAAQ;GACpF,cAAc;GACd,cAAc;GACd,aAAa;GACb,KAAK;GACL,YAAY;GACZ,KAAK;EACP,CAAC;EACD,IAAI,UAAU,eAAe,KAAK,MAAM,IAAI,MAAM,2BAA2B;EAC7E,MAAM,SAAS,KAAK,MAAM,UAAU,KAAK,SAAS,MAAM,CAAC,CAAC,CAAC;EAE3D,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,MAAM,MAAM,WACV;IACE,QAAQ;IACR,MAAM,SAAS,OAAO;IACtB,SAAS;KAAE,gBAAgB;KAAoB,YAAY;IAAU;GACvE,IACC,QAAQ;IACP,QAAQ;KACN,QAAQ;KACR,SAAS,GAAW,MAAc;MAEhC,WADsB;OAAE,QAAQ;OAAQ,MAAM,SAAS,OAAO,YAAY,EAAE,KAAK;OAAK,SAAS,CAAC;MAAE,SAAS,CAAC,CAC3G,CAAC,CAAC,IAAI;KACT;KACA,YAAY;MACV,IAAI,QAAQ;KACd;IACF,CAAC;GACH,CACF;GACA,IAAI,GAAG,SAAS,MAAM;GACtB,IAAI,MAAM,KAAK,UAAU;IAAE,QAAQ;IAAO,KAAK;GAAK,CAAC,CAAC;GACtD,IAAI,IAAI;EACV,CAAC;CACH;CAEA,MAAM,WAA0B;EAE9B,KAAI,MADiB,KAAK,UAAU,qCAAqC,GAAG,EAAA,CACjE,OAAO,SAAS,aAAa,GACtC,MAAM,KAAK,UAAU,4FAA4F,GAAG;CAExH;AACF"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { listContainers, provisionContainer } from "./provision.js";
|
|
2
|
+
import { resolveHostRunner } from "./host-runner.js";
|
|
3
|
+
//#region src/exec-docker/docker-routes.ts
|
|
4
|
+
function sendJson(res, status, body) {
|
|
5
|
+
res.writeHead(status, { "content-type": "application/json" });
|
|
6
|
+
res.end(JSON.stringify(body));
|
|
7
|
+
}
|
|
8
|
+
function readBody(req) {
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
if ((req.headers["content-type"] ?? "") !== "application/json") {
|
|
11
|
+
resolve(null);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const chunks = [];
|
|
15
|
+
let size = 0;
|
|
16
|
+
req.on("data", (chunk) => {
|
|
17
|
+
size += chunk.length;
|
|
18
|
+
if (size > 65536) {
|
|
19
|
+
resolve(null);
|
|
20
|
+
req.destroy();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
chunks.push(chunk);
|
|
24
|
+
});
|
|
25
|
+
req.on("end", () => {
|
|
26
|
+
try {
|
|
27
|
+
resolve(JSON.parse(Buffer.concat(chunks).toString("utf8")));
|
|
28
|
+
} catch {
|
|
29
|
+
resolve(null);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
req.on("error", () => resolve(null));
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function pathSegments(req) {
|
|
36
|
+
return new URL(req.url ?? "/", "http://x").pathname.split("/").filter(Boolean);
|
|
37
|
+
}
|
|
38
|
+
function registerDockerRoutes(ctx) {
|
|
39
|
+
const webServer = ctx.webServer;
|
|
40
|
+
ctx.effect(() => webServer.register({
|
|
41
|
+
kind: "prefix",
|
|
42
|
+
path: "/api/dshb/docker",
|
|
43
|
+
handler: async (req, res) => {
|
|
44
|
+
const segs = pathSegments(req);
|
|
45
|
+
const nodeId = segs[3];
|
|
46
|
+
const action = segs[4];
|
|
47
|
+
const nodeRegistry = ctx.get("nodeRegistry");
|
|
48
|
+
const node = nodeId ? nodeRegistry?.get(nodeId) : void 0;
|
|
49
|
+
if (!node) {
|
|
50
|
+
sendJson(res, 404, {
|
|
51
|
+
ok: false,
|
|
52
|
+
error: "node not found"
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (req.method === "POST" && action === "provision") {
|
|
57
|
+
const provisioner = ctx.get("dshbDockerProvisioner");
|
|
58
|
+
if (provisioner) {
|
|
59
|
+
try {
|
|
60
|
+
const result = await provisioner.provision(nodeId);
|
|
61
|
+
sendJson(res, 201, {
|
|
62
|
+
ok: true,
|
|
63
|
+
containerId: result.containerId,
|
|
64
|
+
name: result.name
|
|
65
|
+
});
|
|
66
|
+
} catch (err) {
|
|
67
|
+
sendJson(res, 502, {
|
|
68
|
+
ok: false,
|
|
69
|
+
error: err instanceof Error ? err.message : String(err)
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const body = await readBody(req);
|
|
75
|
+
const image = String(body?.image ?? "");
|
|
76
|
+
if (!image) {
|
|
77
|
+
sendJson(res, 400, {
|
|
78
|
+
ok: false,
|
|
79
|
+
error: "需要 image"
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const fallbackRunner = await resolveHostRunner(ctx, node);
|
|
84
|
+
if (!fallbackRunner) {
|
|
85
|
+
sendJson(res, 503, {
|
|
86
|
+
ok: false,
|
|
87
|
+
error: "节点执行世界未就绪"
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const result = await provisionContainer(fallbackRunner, {
|
|
93
|
+
image,
|
|
94
|
+
cpus: body?.cpus ? Number(body.cpus) : void 0,
|
|
95
|
+
memoryMB: body?.memoryMB ? Number(body.memoryMB) : void 0,
|
|
96
|
+
name: body?.name ? String(body.name) : void 0
|
|
97
|
+
});
|
|
98
|
+
sendJson(res, 201, {
|
|
99
|
+
ok: true,
|
|
100
|
+
containerId: result.containerId,
|
|
101
|
+
name: result.name
|
|
102
|
+
});
|
|
103
|
+
} catch (err) {
|
|
104
|
+
sendJson(res, 502, {
|
|
105
|
+
ok: false,
|
|
106
|
+
error: err instanceof Error ? err.message : String(err)
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const runner = await resolveHostRunner(ctx, node);
|
|
112
|
+
if (!runner) {
|
|
113
|
+
sendJson(res, 503, {
|
|
114
|
+
ok: false,
|
|
115
|
+
error: "节点执行世界未就绪"
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (req.method === "GET" && action === "containers") {
|
|
120
|
+
sendJson(res, 200, {
|
|
121
|
+
ok: true,
|
|
122
|
+
containers: await listContainers(runner)
|
|
123
|
+
});
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (req.method === "POST" && (action === "restart" || action === "stop" || action === "start" || action === "delete")) {
|
|
127
|
+
const containerId = node.docker?.containerId;
|
|
128
|
+
if (!containerId) {
|
|
129
|
+
sendJson(res, 400, {
|
|
130
|
+
ok: false,
|
|
131
|
+
error: "节点未关联容器"
|
|
132
|
+
});
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
if (action === "delete") {
|
|
137
|
+
const r = await runner.run([
|
|
138
|
+
"docker",
|
|
139
|
+
"rm",
|
|
140
|
+
"-f",
|
|
141
|
+
containerId
|
|
142
|
+
]);
|
|
143
|
+
if (r.code !== 0) throw new Error((r.stderr || r.stdout).trim() || "删除容器失败");
|
|
144
|
+
sendJson(res, 200, {
|
|
145
|
+
ok: true,
|
|
146
|
+
action: "delete"
|
|
147
|
+
});
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (action === "stop") {
|
|
151
|
+
const r = await runner.run([
|
|
152
|
+
"docker",
|
|
153
|
+
"stop",
|
|
154
|
+
containerId
|
|
155
|
+
]);
|
|
156
|
+
if (r.code !== 0) throw new Error((r.stderr || r.stdout).trim() || "停止失败");
|
|
157
|
+
sendJson(res, 200, {
|
|
158
|
+
ok: true,
|
|
159
|
+
action: "stop"
|
|
160
|
+
});
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (action === "start") {
|
|
164
|
+
const r = await runner.run([
|
|
165
|
+
"docker",
|
|
166
|
+
"start",
|
|
167
|
+
containerId
|
|
168
|
+
]);
|
|
169
|
+
if (r.code !== 0) throw new Error((r.stderr || r.stdout).trim() || "启动失败");
|
|
170
|
+
sendJson(res, 200, {
|
|
171
|
+
ok: true,
|
|
172
|
+
action: "start"
|
|
173
|
+
});
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const inspect = await runner.run([
|
|
177
|
+
"docker",
|
|
178
|
+
"inspect",
|
|
179
|
+
"--format",
|
|
180
|
+
"{{.State.Running}}",
|
|
181
|
+
containerId
|
|
182
|
+
]);
|
|
183
|
+
if (inspect.code !== 0) throw new Error("容器不存在或已删除");
|
|
184
|
+
const running = inspect.stdout.trim() === "true";
|
|
185
|
+
const cmd = running ? "restart" : "start";
|
|
186
|
+
const r = await runner.run([
|
|
187
|
+
"docker",
|
|
188
|
+
cmd,
|
|
189
|
+
containerId
|
|
190
|
+
]);
|
|
191
|
+
if (r.code !== 0) throw new Error((r.stderr || r.stdout).trim() || "重启失败");
|
|
192
|
+
sendJson(res, 200, {
|
|
193
|
+
ok: true,
|
|
194
|
+
action: "restart",
|
|
195
|
+
was: running ? "running" : "stopped"
|
|
196
|
+
});
|
|
197
|
+
} catch (err) {
|
|
198
|
+
sendJson(res, 502, {
|
|
199
|
+
ok: false,
|
|
200
|
+
error: err instanceof Error ? err.message : String(err)
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
sendJson(res, 404, {
|
|
206
|
+
ok: false,
|
|
207
|
+
error: "not found"
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
212
|
+
//#endregion
|
|
213
|
+
export { registerDockerRoutes };
|
|
214
|
+
|
|
215
|
+
//# sourceMappingURL=docker-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker-routes.js","names":[],"sources":["../../src/exec-docker/docker-routes.ts"],"sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-host-webserver'\nimport { listContainers, provisionContainer } from './provision.js'\nimport { resolveHostRunner } from './host-runner.js'\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n res.writeHead(status, { 'content-type': 'application/json' })\n res.end(JSON.stringify(body))\n}\n\nfunction readBody(req: IncomingMessage): Promise<Record<string, unknown> | null> {\n return new Promise((resolve) => {\n if ((req.headers['content-type'] ?? '') !== 'application/json') {\n resolve(null)\n return\n }\n const chunks: Buffer[] = []\n let size = 0\n req.on('data', (chunk: Buffer) => {\n size += chunk.length\n if (size > 64 * 1024) {\n resolve(null)\n req.destroy()\n return\n }\n chunks.push(chunk)\n })\n req.on('end', () => {\n try {\n resolve(JSON.parse(Buffer.concat(chunks).toString('utf8')) as Record<string, unknown>)\n } catch {\n resolve(null)\n }\n })\n req.on('error', () => resolve(null))\n })\n}\n\nfunction pathSegments(req: IncomingMessage): string[] {\n return new URL(req.url ?? '/', 'http://x').pathname.split('/').filter(Boolean)\n}\n\ninterface NodeRegistryLike {\n get(id: string): { id: string; type: string; ssh?: unknown; docker?: { containerId?: string; image?: string; mode?: string; resources?: { cpus?: number; memoryMB?: number } } } | undefined\n}\n\nexport function registerDockerRoutes(ctx: Context): void {\n const webServer = ctx.webServer\n ctx.effect(() =>\n webServer.register({\n kind: 'prefix',\n path: '/api/dshb/docker',\n handler: async (req, res) => {\n const segs = pathSegments(req)\n const nodeId = segs[3]\n const action = segs[4]\n\n const nodeRegistry = ctx.get('nodeRegistry') as NodeRegistryLike | undefined\n const node = nodeId ? nodeRegistry?.get(nodeId) : undefined\n if (!node) {\n sendJson(res, 404, { ok: false, error: 'node not found' })\n return\n }\n\n if (req.method === 'POST' && action === 'provision') {\n const provisioner = ctx.get('dshbDockerProvisioner') as { provision(nodeId: string): Promise<{ containerId: string; name: string }> } | undefined\n if (provisioner) {\n try {\n const result = await provisioner.provision(nodeId)\n sendJson(res, 201, { ok: true, containerId: result.containerId, name: result.name })\n } catch (err) {\n sendJson(res, 502, { ok: false, error: err instanceof Error ? err.message : String(err) })\n }\n return\n }\n const body = await readBody(req)\n const image = String(body?.image ?? '')\n if (!image) {\n sendJson(res, 400, { ok: false, error: '需要 image' })\n return\n }\n const fallbackRunner = await resolveHostRunner(ctx, node)\n if (!fallbackRunner) {\n sendJson(res, 503, { ok: false, error: '节点执行世界未就绪' })\n return\n }\n try {\n const result = await provisionContainer(fallbackRunner, {\n image,\n cpus: body?.cpus ? Number(body.cpus) : undefined,\n memoryMB: body?.memoryMB ? Number(body.memoryMB) : undefined,\n name: body?.name ? String(body.name) : undefined,\n })\n sendJson(res, 201, { ok: true, containerId: result.containerId, name: result.name })\n } catch (err) {\n sendJson(res, 502, { ok: false, error: err instanceof Error ? err.message : String(err) })\n }\n return\n }\n\n const runner = await resolveHostRunner(ctx, node)\n\n if (!runner) {\n sendJson(res, 503, { ok: false, error: '节点执行世界未就绪' })\n return\n }\n\n if (req.method === 'GET' && action === 'containers') {\n const containers = await listContainers(runner)\n sendJson(res, 200, { ok: true, containers })\n return\n }\n\n if (req.method === 'POST' && (action === 'restart' || action === 'stop' || action === 'start' || action === 'delete')) {\n const containerId = node.docker?.containerId\n if (!containerId) {\n sendJson(res, 400, { ok: false, error: '节点未关联容器' })\n return\n }\n try {\n if (action === 'delete') {\n const r = await runner.run(['docker', 'rm', '-f', containerId])\n if (r.code !== 0) throw new Error((r.stderr || r.stdout).trim() || '删除容器失败')\n sendJson(res, 200, { ok: true, action: 'delete' })\n return\n }\n if (action === 'stop') {\n const r = await runner.run(['docker', 'stop', containerId])\n if (r.code !== 0) throw new Error((r.stderr || r.stdout).trim() || '停止失败')\n sendJson(res, 200, { ok: true, action: 'stop' })\n return\n }\n if (action === 'start') {\n const r = await runner.run(['docker', 'start', containerId])\n if (r.code !== 0) throw new Error((r.stderr || r.stdout).trim() || '启动失败')\n sendJson(res, 200, { ok: true, action: 'start' })\n return\n }\n const inspect = await runner.run(['docker', 'inspect', '--format', '{{.State.Running}}', containerId])\n if (inspect.code !== 0) throw new Error('容器不存在或已删除')\n const running = inspect.stdout.trim() === 'true'\n const cmd = running ? 'restart' : 'start'\n const r = await runner.run(['docker', cmd, containerId])\n if (r.code !== 0) throw new Error((r.stderr || r.stdout).trim() || '重启失败')\n sendJson(res, 200, { ok: true, action: 'restart', was: running ? 'running' : 'stopped' })\n } catch (err) {\n sendJson(res, 502, { ok: false, error: err instanceof Error ? err.message : String(err) })\n }\n return\n }\n\n sendJson(res, 404, { ok: false, error: 'not found' })\n },\n }),\n )\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { DockerBackend } from "./docker-backend.js";
|
|
2
|
+
//#region src/exec-docker/fs-provider.d.ts
|
|
3
|
+
declare class DockerFileSystem {
|
|
4
|
+
private readonly client;
|
|
5
|
+
constructor(client: DockerBackend);
|
|
6
|
+
resolve(path: string): Promise<string>;
|
|
7
|
+
processPath(target: string): string;
|
|
8
|
+
fileUrl(target: string): string;
|
|
9
|
+
contains(parent: string, child: string): boolean;
|
|
10
|
+
stat(target: string, _signal?: AbortSignal): Promise<{
|
|
11
|
+
size: number;
|
|
12
|
+
mtime: number;
|
|
13
|
+
isDirectory: boolean;
|
|
14
|
+
isFile: boolean;
|
|
15
|
+
} | undefined>;
|
|
16
|
+
lstat(path: string, _opts?: {
|
|
17
|
+
cwd?: string;
|
|
18
|
+
}, _signal?: AbortSignal): Promise<{
|
|
19
|
+
size: number;
|
|
20
|
+
mtime: number;
|
|
21
|
+
isDirectory: boolean;
|
|
22
|
+
isFile: boolean;
|
|
23
|
+
} | undefined>;
|
|
24
|
+
readText(target: string, _signal?: AbortSignal): Promise<string>;
|
|
25
|
+
streamText(target: string, _signal?: AbortSignal): Promise<AsyncIterable<string>>;
|
|
26
|
+
readBytes(target: string, _signal: AbortSignal | undefined, maxBytes: number): Promise<Uint8Array>;
|
|
27
|
+
listDir(target: string, _signal?: AbortSignal): Promise<Array<{
|
|
28
|
+
name: string;
|
|
29
|
+
path: string;
|
|
30
|
+
isDirectory: boolean;
|
|
31
|
+
isFile: boolean;
|
|
32
|
+
isSymlink: boolean;
|
|
33
|
+
size: number;
|
|
34
|
+
mtime: number;
|
|
35
|
+
}>>;
|
|
36
|
+
writeText(target: string, content: string, _expected?: unknown, _signal?: AbortSignal, _policy?: unknown): Promise<{
|
|
37
|
+
operation: 'create' | 'update';
|
|
38
|
+
version: string;
|
|
39
|
+
before: string | null;
|
|
40
|
+
after: string;
|
|
41
|
+
}>;
|
|
42
|
+
editText(target: string, edit: unknown, _expected?: unknown, _signal?: AbortSignal, _policy?: unknown): Promise<{
|
|
43
|
+
version: string;
|
|
44
|
+
before: string;
|
|
45
|
+
after: string;
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { DockerFileSystem };
|
|
50
|
+
//# sourceMappingURL=fs-provider.d.ts.map
|