Compare commits
3 Commits
608b57af90
...
fix/repo-o
| Author | SHA1 | Date | |
|---|---|---|---|
| 34bc7b4d0c | |||
| 92b7d50817 | |||
| 44a0826a7d |
@@ -35,7 +35,9 @@ export class Terminal extends Component<Props, State> {
|
|||||||
const options = new URLSearchParams(decodeURIComponent(window.location.search));
|
const options = new URLSearchParams(decodeURIComponent(window.location.search));
|
||||||
|
|
||||||
this.isDockerType = options.get('type') === 'docker';
|
this.isDockerType = options.get('type') === 'docker';
|
||||||
this.apiBaseUrl = `http://${options.get('domain')}:${options.get('port')}/${options.get('user')}/${options.get('repo')}`;
|
// Use repo_owner if available, otherwise fall back to user
|
||||||
|
const repoOwner = options.get('repo_owner') || options.get('user');
|
||||||
|
this.apiBaseUrl = `http://${options.get('domain')}:${options.get('port')}/${repoOwner}/${options.get('repo')}`;
|
||||||
this.apiParams = new URLSearchParams({
|
this.apiParams = new URLSearchParams({
|
||||||
repo: options.get('repoid') as string,
|
repo: options.get('repoid') as string,
|
||||||
user: options.get('userid') as string,
|
user: options.get('userid') as string,
|
||||||
|
|||||||
@@ -112,7 +112,6 @@ export class Xterm {
|
|||||||
private containerStatus = "";
|
private containerStatus = "";
|
||||||
private attachCommandSent = false;
|
private attachCommandSent = false;
|
||||||
private attachCommandSentAt?: number;
|
private attachCommandSentAt?: number;
|
||||||
private ptyOutputReceived = false;
|
|
||||||
constructor(
|
constructor(
|
||||||
private options: XtermOptions,
|
private options: XtermOptions,
|
||||||
private sendCb: () => void
|
private sendCb: () => void
|
||||||
@@ -277,7 +276,6 @@ export class Xterm {
|
|||||||
@bind
|
@bind
|
||||||
public connect() {
|
public connect() {
|
||||||
this.socket = new WebSocket(this.options.wsUrl, ['tty']);
|
this.socket = new WebSocket(this.options.wsUrl, ['tty']);
|
||||||
this.ptyOutputReceived = false;
|
|
||||||
const { socket, register } = this;
|
const { socket, register } = this;
|
||||||
|
|
||||||
socket.binaryType = 'arraybuffer';
|
socket.binaryType = 'arraybuffer';
|
||||||
@@ -312,7 +310,6 @@ export class Xterm {
|
|||||||
this.doReconnect = this.reconnect;
|
this.doReconnect = this.reconnect;
|
||||||
this.initListeners();
|
this.initListeners();
|
||||||
terminal.focus();
|
terminal.focus();
|
||||||
this.tryExecuteAttachCommand();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
@@ -343,43 +340,6 @@ export class Xterm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
|
||||||
private tryExecuteAttachCommand() {
|
|
||||||
console.log('[Xterm] tryExecuteAttachCommand called:', {
|
|
||||||
attachCommandSent: this.attachCommandSent,
|
|
||||||
connectStatus: this.connectStatus,
|
|
||||||
hasCommand: !!(this.postAttachCommand && this.postAttachCommand.length > 0),
|
|
||||||
socketReady: this.socket?.readyState === WebSocket.OPEN,
|
|
||||||
ptyOutputReceived: this.ptyOutputReceived
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.attachCommandSent || this.connectStatus) {
|
|
||||||
console.log('[Xterm] Skipping: command already sent or connected');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.postAttachCommand || this.postAttachCommand.length === 0) {
|
|
||||||
console.log('[Xterm] Skipping: no command available');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.socket?.readyState !== WebSocket.OPEN) {
|
|
||||||
console.log('[Xterm] Skipping: WebSocket not ready, state:', this.socket?.readyState);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.ptyOutputReceived) {
|
|
||||||
console.log('[Xterm] Skipping: ttyd not ready yet (waiting for first output)');
|
|
||||||
return; // Wait for TTY readiness confirm via output
|
|
||||||
}
|
|
||||||
|
|
||||||
const cmd = this.postAttachCommand[0];
|
|
||||||
if (cmd) {
|
|
||||||
console.log('[Xterm] ✅ All conditions met, executing attach command...');
|
|
||||||
this.sendData(cmd + "\n");
|
|
||||||
this.attachCommandSent = true;
|
|
||||||
this.attachCommandSentAt = Date.now();
|
|
||||||
console.log('[Xterm] Command sent at:', new Date(this.attachCommandSentAt).toISOString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 URL 查询参数
|
* 获取 URL 查询参数
|
||||||
*/
|
*/
|
||||||
@@ -433,8 +393,14 @@ export class Xterm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 执行连接容器的命令(只执行一次)
|
// 执行连接容器的命令(只执行一次)
|
||||||
this.postAttachCommand = data.command.split('\n');
|
const parts = data.command.split('\n');
|
||||||
this.tryExecuteAttachCommand();
|
if (parts[0] && !this.connectStatus) {
|
||||||
|
console.log('[Xterm] Successfully loaded connection command, executing...');
|
||||||
|
this.sendData(parts[0]+"\n");
|
||||||
|
this.attachCommandSent = true;
|
||||||
|
this.attachCommandSentAt = Date.now();
|
||||||
|
}
|
||||||
|
this.postAttachCommand = parts;
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error(`[Xterm] Error loading command (attempt ${retryCount + 1}/${maxRetries}):`, error);
|
console.error(`[Xterm] Error loading command (attempt ${retryCount + 1}/${maxRetries}):`, error);
|
||||||
@@ -499,66 +465,48 @@ export class Xterm {
|
|||||||
const data = rawData.slice(1);
|
const data = rawData.slice(1);
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case Command.OUTPUT:
|
case Command.OUTPUT:
|
||||||
if (!this.ptyOutputReceived) {
|
|
||||||
this.ptyOutputReceived = true;
|
|
||||||
console.log('[Xterm] ✅ ttyd is now ready (received first output), attempting to execute attach command');
|
|
||||||
this.tryExecuteAttachCommand();
|
|
||||||
}
|
|
||||||
|
|
||||||
const decodedData = textDecoder.decode(data);
|
const decodedData = textDecoder.decode(data);
|
||||||
console.log('[ttyd] output:', decodedData);
|
console.log('[ttyd] output:', decodedData);
|
||||||
const compactOutput = decodedData.replace(/\s/g, '');
|
const compactOutput = decodedData.replace(/\s/g, '');
|
||||||
const { options } = this.getUrlParams();
|
const { options } = this.getUrlParams();
|
||||||
if (options.get('type') === 'docker') {
|
if (options.get('type') === 'docker') {
|
||||||
// 保存host的标题
|
// 保存host的标题
|
||||||
const pureContent = decodedData.replace(/\u001B\[[0-9;?]*[ -\/]*[@-~]/g, '').replace(/\u0007/g, '').trim();
|
if (this.hostTitle === ''){
|
||||||
if (this.hostTitle === '' && pureContent.length > 0){
|
|
||||||
this.hostTitle = compactOutput;
|
this.hostTitle = compactOutput;
|
||||||
console.log('[Xterm] Host title captured:', this.hostTitle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测是否退出devcontainer,标题等于host的标题
|
// 检测是否退出devcontainer,标题等于host的标题
|
||||||
if (this.connectStatus && this.hostTitle && compactOutput.includes(this.hostTitle)){
|
if (this.connectStatus && compactOutput.includes(this.hostTitle)){
|
||||||
console.log('[Xterm] Detected exit to host shell');
|
|
||||||
this.connectStatus = false;
|
this.connectStatus = false;
|
||||||
this.connectionMessageBuffer = '';
|
this.connectionMessageBuffer = '';
|
||||||
this.attachCommandSent = false;
|
this.attachCommandSent = false;
|
||||||
this.attachCommandSentAt = undefined;
|
this.attachCommandSentAt = undefined;
|
||||||
this.postAttachCommandStatus = false;
|
this.postAttachCommandStatus = false;
|
||||||
this.ptyOutputReceived = false; // 重置 PTY 状态
|
|
||||||
}
|
}
|
||||||
|
// 检测连接完成:监听 "Successfully connected to the devcontainer" 消息
|
||||||
if (this.connectStatus) {
|
// 这条消息是由连接命令中的 echo "$WEB_TERMINAL_HELLO" 输出的
|
||||||
try {
|
if (!this.connectStatus) {
|
||||||
this.writeFunc(data);
|
const sanitizedOutput = this.stripAnsi(decodedData).replace(/\r/g, '\n');
|
||||||
} catch (e) {
|
const combinedOutput = this.connectionMessageBuffer + sanitizedOutput;
|
||||||
console.error('[Xterm] writeFunc error:', e);
|
const segments = combinedOutput.split(/\n/);
|
||||||
}
|
this.connectionMessageBuffer = segments.pop() ?? '';
|
||||||
} else {
|
const hasSuccessLine = segments.some(line => line.trim() === 'Successfully connected to the devcontainer');
|
||||||
// 未连接状态:缓冲所有输出
|
if (hasSuccessLine) {
|
||||||
this.connectionMessageBuffer += decodedData;
|
|
||||||
|
|
||||||
const successMarker = 'Successfully connected to the devcontainer';
|
|
||||||
// 尝试在 buffer 中查找成功标记
|
|
||||||
const markerIndex = this.connectionMessageBuffer.indexOf(successMarker);
|
|
||||||
|
|
||||||
if (markerIndex !== -1) {
|
|
||||||
console.log('[Xterm] Connection established, flushing buffer.');
|
|
||||||
this.connectStatus = true;
|
this.connectStatus = true;
|
||||||
this.terminal.options.disableStdin = false;
|
|
||||||
|
|
||||||
const validOutput = this.connectionMessageBuffer.substring(markerIndex);
|
|
||||||
this.writeData(validOutput);
|
|
||||||
this.connectionMessageBuffer = '';
|
this.connectionMessageBuffer = '';
|
||||||
}
|
this.attachCommandSentAt = undefined;
|
||||||
|
console.log('[Xterm] Connection established, enabling terminal input');
|
||||||
if (this.connectionMessageBuffer.length > 20000) {
|
// 确保终端输入已启用
|
||||||
console.warn('[Xterm] Buffer overflow protection. Flushing all.');
|
this.terminal.options.disableStdin = false;
|
||||||
this.writeData(this.connectionMessageBuffer);
|
|
||||||
this.connectionMessageBuffer = '';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 连接完成之前,过滤掉 docker exec 命令的标题输出(ANSI 码和 docker-H 开头的输出)
|
||||||
|
if (
|
||||||
|
!(this.connectStatus === false &&
|
||||||
|
(textDecoder.decode(data).includes('\x1b') ||
|
||||||
|
textDecoder.decode(data).replace(/\s/g, '').includes('docker-H')))
|
||||||
|
){
|
||||||
|
this.writeFunc(data);
|
||||||
|
}
|
||||||
// 连接完成且出现容器的标题,且没有执行过postAttach命令
|
// 连接完成且出现容器的标题,且没有执行过postAttach命令
|
||||||
if (this.connectStatus && compactOutput.includes(this.workdir) && !this.postAttachCommandStatus){
|
if (this.connectStatus && compactOutput.includes(this.workdir) && !this.postAttachCommandStatus){
|
||||||
console.log('[Xterm] Detected workdir in output, executing postAttachCommand');
|
console.log('[Xterm] Detected workdir in output, executing postAttachCommand');
|
||||||
|
|||||||
32530
src/html.h
generated
32530
src/html.h
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user