mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-12-15 00:26:23 +00:00
Update appImage
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"""
|
||||||
|
|||||||
Reference in New Issue
Block a user