Update appImage

This commit is contained in:
MacRimi
2025-11-22 21:43:14 +01:00
parent 76d22f0cb5
commit ebe3a51398
2 changed files with 65 additions and 91 deletions

View File

@@ -288,8 +288,6 @@ export const TerminalPanel: React.FC<TerminalPanelProps> = ({ websocketUrl, onCl
cursorBlink: true, cursorBlink: true,
scrollback: 2000, scrollback: 2000,
disableStdin: false, disableStdin: false,
cols: isMobile ? 40 : layout === "grid" ? 60 : 120,
rows: isMobile ? 20 : layout === "grid" ? 15 : 30,
theme: { theme: {
background: "#000000", background: "#000000",
foreground: "#ffffff", foreground: "#ffffff",
@@ -325,13 +323,23 @@ export const TerminalPanel: React.FC<TerminalPanelProps> = ({ websocketUrl, onCl
if (xtermViewport) xtermViewport.style.padding = "0" if (xtermViewport) xtermViewport.style.padding = "0"
if (xtermScreen) xtermScreen.style.padding = "0" if (xtermScreen) xtermScreen.style.padding = "0"
fitAddon.fit() fitAddon.fit()
console.log(`[v0] Terminal fitted: ${term.cols}x${term.rows}`)
const cols = term.cols // Send resize to backend via HTTP
const rows = term.rows const apiUrl = getApiUrl()
if (ws.readyState === WebSocket.OPEN) { fetch(`${apiUrl}/api/terminal/${terminal.id}/resize`, {
ws.send(`\x1b[8;${rows};${cols}t`) method: "POST",
} headers: { "Content-Type": "application/json" },
}, 10) body: JSON.stringify({ cols: term.cols, rows: term.rows }),
})
.then((res) => res.json())
.then((data) => {
console.log(`[v0] Backend PTY resized:`, data)
})
.catch((err) => {
console.error(`[v0] Error resizing backend PTY:`, err)
})
}, 100)
const wsUrl = websocketUrl || getWebSocketUrl() const wsUrl = websocketUrl || getWebSocketUrl()
const ws = new WebSocket(wsUrl) const ws = new WebSocket(wsUrl)
@@ -367,9 +375,17 @@ export const TerminalPanel: React.FC<TerminalPanelProps> = ({ websocketUrl, onCl
fitAddon.fit() fitAddon.fit()
const cols = term.cols const cols = term.cols
const rows = term.rows const rows = term.rows
if (ws.readyState === WebSocket.OPEN) { console.log(`[v0] Window resized, terminal now: ${cols}x${rows}`)
ws.send(`\x1b[8;${rows};${cols}t`)
} // Send resize to backend via HTTP
const apiUrl = getApiUrl()
fetch(`${apiUrl}/api/terminal/${terminal.id}/resize`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ cols, rows }),
}).catch((err) => {
console.error(`[v0] Error resizing backend PTY:`, err)
})
} catch { } catch {
// Ignore resize errors // Ignore resize errors
} }

View File

@@ -20,79 +20,8 @@ import requests
terminal_bp = Blueprint('terminal', __name__) terminal_bp = Blueprint('terminal', __name__)
sock = Sock() sock = Sock()
# Active terminal sessions # Active terminal sessions - now stores session by session_id string
active_sessions = {} sessions = {}
@terminal_bp.route('/api/terminal/health', methods=['GET'])
def terminal_health():
"""Health check for terminal service"""
return {'success': True, 'active_sessions': len(active_sessions)}
@terminal_bp.route('/api/terminal/search-command', methods=['GET'])
def search_command():
"""Proxy endpoint for cheat.sh API to avoid CORS issues"""
query = request.args.get('q', '')
if not query or len(query) < 2:
return jsonify({'error': 'Query too short'}), 400
try:
url = f'https://cht.sh/{query.replace(" ", "+")}?QT'
headers = {
'User-Agent': 'curl/7.68.0'
}
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
content = response.text
examples = []
current_description = []
for line in content.split('\n'):
stripped = line.strip()
# Ignorar líneas vacías
if not stripped:
continue
# Si es un comentario
if stripped.startswith('#'):
# Acumular descripciones
current_description.append(stripped[1:].strip())
# Si no es comentario, es un comando
elif stripped and not stripped.startswith('http'):
# Unir las descripciones acumuladas
description = ' '.join(current_description) if current_description else ''
examples.append({
'description': description,
'command': stripped
})
# Resetear descripciones para el siguiente comando
current_description = []
return jsonify({
'success': True,
'examples': examples
})
else:
return jsonify({
'success': False,
'error': f'API returned status {response.status_code}'
}), response.status_code
except requests.Timeout:
return jsonify({
'success': False,
'error': 'Request timeout'
}), 504
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
def set_winsize(fd, rows, cols): def set_winsize(fd, rows, cols):
"""Set terminal window size""" """Set terminal window size"""
@@ -121,6 +50,33 @@ def read_and_forward_output(master_fd, ws):
print(f"Error reading from PTY: {e}") print(f"Error reading from PTY: {e}")
break break
@terminal_bp.route('/api/terminal/health', methods=['GET'])
def terminal_health():
"""Health check for terminal service"""
return {'success': True, 'active_sessions': len(sessions)}
@terminal_bp.route('/api/terminal/<session_id>/resize', methods=['POST'])
def resize_terminal(session_id):
"""Resize the PTY for a given terminal session."""
if session_id not in sessions:
return jsonify({'error': 'Session not found'}), 404
try:
data = request.get_json()
cols = int(data.get('cols', 120))
rows = int(data.get('rows', 30))
# Resize the PTY to match the frontend terminal dimensions
master_fd = sessions[session_id]['master_fd']
set_winsize(master_fd, rows, cols)
print(f"[v0] Terminal {session_id} resized to {cols}x{rows}")
return jsonify({'status': 'success', 'cols': cols, 'rows': rows})
except Exception as e:
print(f"Error resizing terminal {session_id}: {e}")
return jsonify({'error': str(e)}), 500
@sock.route('/ws/terminal') @sock.route('/ws/terminal')
def terminal_websocket(ws): def terminal_websocket(ws):
"""WebSocket endpoint for terminal sessions""" """WebSocket endpoint for terminal sessions"""
@@ -139,8 +95,8 @@ def terminal_websocket(ws):
env=dict(os.environ, TERM='xterm-256color', PS1='\\u@\\h:\\w\\$ ') env=dict(os.environ, TERM='xterm-256color', PS1='\\u@\\h:\\w\\$ ')
) )
session_id = id(ws) session_id = str(int(time.time() * 1000))
active_sessions[session_id] = { sessions[session_id] = {
'process': shell_process, 'process': shell_process,
'master_fd': master_fd 'master_fd': master_fd
} }
@@ -149,8 +105,10 @@ def terminal_websocket(ws):
flags = fcntl.fcntl(master_fd, fcntl.F_GETFL) flags = fcntl.fcntl(master_fd, fcntl.F_GETFL)
fcntl.fcntl(master_fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) fcntl.fcntl(master_fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
# Set initial terminal size set_winsize(master_fd, 30, 80)
set_winsize(master_fd, 30, 120)
# Send session_id to frontend
ws.send(f"\x1b]0;SESSION_ID:{session_id}\x07")
# Start thread to read PTY output and forward to WebSocket # Start thread to read PTY output and forward to WebSocket
output_thread = threading.Thread( output_thread = threading.Thread(
@@ -176,7 +134,7 @@ def terminal_websocket(ws):
if len(parts) >= 2: if len(parts) >= 2:
rows, cols = int(parts[0]), int(parts[1]) rows, cols = int(parts[0]), int(parts[1])
set_winsize(master_fd, rows, cols) set_winsize(master_fd, rows, cols)
print(f"[Terminal] Resized to {rows}x{cols}") print(f"[v0] Terminal resized via WebSocket to {rows}x{cols}")
continue continue
except Exception as e: except Exception as e:
print(f"Error parsing resize: {e}") print(f"Error parsing resize: {e}")
@@ -216,8 +174,8 @@ def terminal_websocket(ws):
except: except:
pass pass
if session_id in active_sessions: if session_id in sessions:
del active_sessions[session_id] del sessions[session_id]
def init_terminal_routes(app): def init_terminal_routes(app):
"""Initialize terminal routes with Flask app""" """Initialize terminal routes with Flask app"""