修复由于webterminal轮询终止的误判,导致需要刷新的问题 #2

Merged
mengning merged 2 commits from fix/web-terminal-refresh into main 2025-12-08 10:13:30 +00:00
2 changed files with 16254 additions and 16211 deletions
Showing only changes of commit 361cf601ce - Show all commits

View File

@@ -104,11 +104,14 @@ export class Xterm {
private intervalID: NodeJS.Timeout; private intervalID: NodeJS.Timeout;
private writeFunc = (data: ArrayBuffer) => this.writeData(new Uint8Array(data)); private writeFunc = (data: ArrayBuffer) => this.writeData(new Uint8Array(data));
private connectStatus = false; private connectStatus = false;
private connectionMessageBuffer = "";
private hostTitle = ""; private hostTitle = "";
private postAttachCommand = []; private postAttachCommand = [];
private postAttachCommandStatus = false; private postAttachCommandStatus = false;
private workdir = ""; private workdir = "";
private containerStatus = ""; private containerStatus = "";
private attachCommandSent = false;
private attachCommandSentAt?: number;
private beforeCommand?: string; private beforeCommand?: string;
constructor( constructor(
private options: XtermOptions, private options: XtermOptions,
@@ -367,13 +370,18 @@ export class Xterm {
} }
this.containerStatus = data.status; this.containerStatus = data.status;
} else { } else {
if(this.containerStatus !== '4'){ if (this.containerStatus !== '4'){
this.writeData("\x1b[31mCreation completed. Please refresh the page to connect to the devcontainer\x1b[0m"); this.writeData("\x1b[31mCreation completed.\x1b[0m\r\n");
} }
this.containerStatus = data.status; this.containerStatus = data.status;
if (data.status === '4') { if (data.status === '4') {
const parts = data.command.split('\n'); const parts = data.command.split('\n');
const shouldResend = this.attachCommandSent && this.attachCommandSentAt !== undefined && Date.now() - this.attachCommandSentAt > 5000;
if ((!this.attachCommandSent || shouldResend) && !this.connectStatus && parts[0]) {
this.sendData(parts[0]+"\n"); this.sendData(parts[0]+"\n");
this.attachCommandSent = true;
this.attachCommandSentAt = Date.now();
}
this.postAttachCommand = parts; this.postAttachCommand = parts;
} }
} }
@@ -428,7 +436,9 @@ export class Xterm {
const data = rawData.slice(1); const data = rawData.slice(1);
switch (cmd) { switch (cmd) {
case Command.OUTPUT: case Command.OUTPUT:
console.log('[ttyd] output:', textDecoder.decode(data)); const decodedData = textDecoder.decode(data);
console.log('[ttyd] output:', decodedData);
const compactOutput = decodedData.replace(/\s/g, '');
const options = new URLSearchParams(decodeURIComponent(window.location.search)); const options = new URLSearchParams(decodeURIComponent(window.location.search));
const params = new URLSearchParams({ const params = new URLSearchParams({
repo: options.get('repoid') as string, repo: options.get('repoid') as string,
@@ -436,21 +446,34 @@ export class Xterm {
}); });
if (options.get('type') === 'docker') { if (options.get('type') === 'docker') {
// 保存host的标题 // 保存host的标题
if (this.hostTitle === ""){ if (this.hostTitle === ''){
this.hostTitle = textDecoder.decode(data).replace(/\s/g, ''); this.hostTitle = compactOutput;
} }
// 检测是否退出devcontainer标题等于host的标题 // 检测是否退出devcontainer标题等于host的标题
if (this.connectStatus && textDecoder.decode(data).replace(/\s/g, '').includes(this.hostTitle)){ if (this.connectStatus && compactOutput.includes(this.hostTitle)){
this.connectStatus = false this.connectStatus = false;
this.connectionMessageBuffer = '';
this.attachCommandSent = false;
this.attachCommandSentAt = undefined;
this.postAttachCommandStatus = false;
} }
// this.connectStatus = true 连接完成 // this.connectStatus = true 连接完成
if ( //由于第二条docker命令中包含Successfully connected to the devcontainer,需要过滤否则会导致轮询终止卡在状态2
this.connectStatus === false && if (!this.connectStatus) {
textDecoder.decode(data).replace(/\s/g, '').includes('Successfully connected to the devcontainer'.replace(/\s/g, '')) const sanitizedOutput = this.stripAnsi(decodedData).replace(/\r/g, '\n');
) { const combinedOutput = this.connectionMessageBuffer + sanitizedOutput;
const segments = combinedOutput.split(/\n/);
this.connectionMessageBuffer = segments.pop() ?? '';
const hasSuccessLine = segments.some(line => line.trim() === 'Successfully connected to the devcontainer');
if (hasSuccessLine) {
this.connectStatus = true; this.connectStatus = true;
this.connectionMessageBuffer = '';
this.attachCommandSentAt = undefined;
if (this.intervalID) {
clearInterval(this.intervalID); clearInterval(this.intervalID);
} }
}
}
// 连接完成之前不输出标题和docker命令 // 连接完成之前不输出标题和docker命令
if ( if (
!(this.connectStatus === false && !(this.connectStatus === false &&
@@ -460,9 +483,9 @@ export class Xterm {
this.writeFunc(data); this.writeFunc(data);
} }
// 连接完成且出现容器的标题且没有执行过postAttach命令 // 连接完成且出现容器的标题且没有执行过postAttach命令
if (this.connectStatus && textDecoder.decode(data).replace(/\s/g, '').includes(this.workdir) && !this.postAttachCommandStatus){ if (this.connectStatus && compactOutput.includes(this.workdir) && !this.postAttachCommandStatus){
for (let i = 1; i < this.postAttachCommand.length; i++){ for (let i = 1; i < this.postAttachCommand.length; i++){
this.sendData(this.postAttachCommand[i]+"\n"); this.sendData(this.postAttachCommand[i]+'\n');
} }
this.postAttachCommandStatus = true; this.postAttachCommandStatus = true;
} }
@@ -655,4 +678,8 @@ export class Xterm {
break; break;
} }
} }
private stripAnsi(input: string): string {
return input.replace(/\u001B\[[0-9;?]*[ -\/]*[@-~]/g, '').replace(/\u0007/g, '');
}
} }

32406
src/html.h generated

File diff suppressed because it is too large Load Diff