Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 68 additions & 13 deletions agent/app/api/v2/terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"net/http"
"strconv"
"strings"
"time"

"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
Expand All @@ -19,11 +20,13 @@ import (
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
gossh "golang.org/x/crypto/ssh"
)

// @Tags Terminal
// @Summary Ws local terminal
// @Param command query string false "command"
// @Param session query string false "session id to reattach"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
Expand All @@ -36,6 +39,8 @@ func (b *BaseApi) WsLocalTerminal(c *gin.Context) {
// @Summary Ws host SSH
// @Param id query integer false "id"
// @Param command query string false "command"
// @Param session query string false "session id to reattach"
// @Param title query string false "session title shown in the session list"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
Expand Down Expand Up @@ -122,25 +127,75 @@ func (b *BaseApi) runSSHSession(c *gin.Context, connect func() (*ssh.SSHClient,
}
defer wsConn.Close()

client, clientErr := connect()
if wshandleError(wsConn, errors.WithMessage(clientErr, "failed to set up the connection. Please check the host information")) {
return
hostID, _ := strconv.Atoi(c.DefaultQuery("id", "0"))
opts := terminal.SessionOptions{
Owner: loadAuditUser(c),
Title: sanitizeTerminalTitle(c.Query("title")),
HostID: uint(max(hostID, 0)),
Cols: cols,
Rows: rows,
InitCmd: command,
}
err := terminal.Serve(wsConn, strings.TrimSpace(c.Query("session")), opts, func() (*gossh.Client, error) {
client, err := connect()
if err != nil {
return nil, errors.WithMessage(err, "failed to set up the connection. Please check the host information")
}
return client.Client, nil
})
if err != nil {
_ = wshandleError(wsConn, err)
}
defer client.Close()
}

sws, err := terminal.NewLogicSshWsSession(cols, rows, client.Client, wsConn, command)
if wshandleError(wsConn, err) {
// @Tags Terminal
// @Summary List the caller's live terminal sessions
// @Success 200 {array} terminal.Info
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /hosts/terminal/sessions/search [post]
func (b *BaseApi) SearchTerminalSessions(c *gin.Context) {
helper.SuccessWithData(c, terminal.List(loadAuditUser(c)))
}

// @Tags Terminal
// @Summary Close a terminal session
// @Accept json
// @Param request body dto.TerminalSessionClose true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /hosts/terminal/sessions/close [post]
func (b *BaseApi) CloseTerminalSession(c *gin.Context) {
var req dto.TerminalSessionClose
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
defer sws.Close()

quitChan := make(chan bool, 3)
sws.Start(quitChan)
go sws.Wait(quitChan)
if err := terminal.CloseSession(req.ID, loadAuditUser(c)); err != nil {
helper.BadRequest(c, err)
return
}
helper.Success(c)
}

<-quitChan
// @Tags Terminal
// @Summary Close every terminal session (panel user logged out)
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /hosts/terminal/sessions/closeAll [post]
func (b *BaseApi) CloseAllTerminalSessions(c *gin.Context) {
terminal.CloseAll()
helper.Success(c)
}

closeTerminalConn(wsConn)
// sanitizeTerminalTitle keeps the title a short single line.
func sanitizeTerminalTitle(title string) string {
title = strings.Join(strings.Fields(title), " ")
if r := []rune(title); len(r) > 64 {
title = string(r[:64])
}
return title
}

func closeTerminalConn(wsConn *websocket.Conn) {
Expand Down
5 changes: 5 additions & 0 deletions agent/app/dto/terminal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dto

type TerminalSessionClose struct {
ID string `json:"id" validate:"required"`
}
1 change: 1 addition & 0 deletions agent/i18n/lang/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ XfsNotFound: 'xfs not found; install xfsprogs first'
# terminal
TerminalAIBlockedRiskyCommand: 'blocked risky command: {{ .command }}'
TerminalAIThinking: 'AI is thinking...'
TerminalOutputTruncated: '[output truncated, showing recent output only]'
TerminalAIReadyToExecute: 'Thinking complete, press Enter to execute (duration: {{ .duration }}, tokens: {{ .tokens }})'
TerminalAIRequestFailed: 'AI request failed: {{ .err }}'

Expand Down
1 change: 1 addition & 0 deletions agent/i18n/lang/es-ES.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ XfsNotFound: 'No se detectó el sistema de archivos xfs instale xfsprogs primero
# terminal
TerminalAIBlockedRiskyCommand: 'Comando de riesgo bloqueado: {{ .command }}'
TerminalAIThinking: 'La IA está pensando...'
TerminalOutputTruncated: '[salida truncada, se muestra solo la salida reciente]'
TerminalAIReadyToExecute: 'Pensamiento completado, pulsa Enter para ejecutar (duración: {{ .duration }}, token: {{ .tokens }})'
TerminalAIRequestFailed: 'La solicitud de AI ha fallado: {{ .err }}'

Expand Down
1 change: 1 addition & 0 deletions agent/i18n/lang/fa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ XfsNotFound: 'xfs یافت نشد؛ ابتدا xfsprogs را نصب کنید'
# ترمینال
TerminalAIBlockedRiskyCommand: 'دستور پرخطر مسدود شد: {{ .command }}'
TerminalAIThinking: 'هوش مصنوعی در حال فکر کردن است...'
TerminalOutputTruncated: '[خروجی کوتاه شد، فقط خروجی اخیر نمایش داده می‌شود]'
TerminalAIReadyToExecute: 'تفکر کامل شد، برای اجرا Enter را فشار دهید (مدت زمان: {{ .duration }}، توکن‌ها: {{ .tokens }})'
TerminalAIRequestFailed: 'درخواست هوش مصنوعی ناموفق بود: {{ .err }}'

Expand Down
1 change: 1 addition & 0 deletions agent/i18n/lang/ja.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ XfsNotFound: 'xfs ファイルシステムが検出されませんでした、
# ターミナル
TerminalAIBlockedRiskyCommand: '危険なコマンドをブロックしました: {{ .command }}'
TerminalAIThinking: 'AI が考えています...'
TerminalOutputTruncated: '[出力は切り詰められました。最近の出力のみ表示しています]'
TerminalAIReadyToExecute: '思考が完了しました。Enter で実行してください(所要時間 {{ .duration }}、token: {{ .tokens }})'
TerminalAIRequestFailed: 'AI リクエストに失敗しました: {{ .err }}'

Expand Down
1 change: 1 addition & 0 deletions agent/i18n/lang/ko.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ XfsNotFound: 'xfs 파일 시스템이 감지되지 않았습니다, 먼저 xfspr
# 터미널
TerminalAIBlockedRiskyCommand: '위험한 명령이 차단되었습니다: {{ .command }}'
TerminalAIThinking: 'AI가 생각 중입니다...'
TerminalOutputTruncated: '[출력이 잘렸습니다. 최근 출력만 표시합니다]'
TerminalAIReadyToExecute: '생각이 완료되었습니다. Enter를 눌러 실행하세요 (소요 시간 {{ .duration }}, token: {{ .tokens }})'
TerminalAIRequestFailed: 'AI 요청 실패: {{ .err }}'

Expand Down
1 change: 1 addition & 0 deletions agent/i18n/lang/lo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ XfsNotFound: 'ບໍ່ພົບ xfs; ກະລຸນາຕິດຕັ້ງ xf
# terminal
TerminalAIBlockedRiskyCommand: 'ບລັອກຄຳສັ່ງທີ່ມີຄວາມສ່ຽງ: {{ .command }}'
TerminalAIThinking: 'AI ກຳລັງຄິດ...'
TerminalOutputTruncated: '[ຜົນລັບຖືກຕັດ, ສະແດງສະເພາະຜົນລັບຫຼ້າສຸດ]'
TerminalAIReadyToExecute: 'ຄິດສຳເລັດແລ້ວ, ກົດ Enter ເພື່ອປະຕິບັດ (ໃຊ້ເວລາ: {{ .duration }}, ໂທເຄັນ: {{ .tokens }})'
TerminalAIRequestFailed: 'ຄຳຮ້ອງຂໍ AI ລົ້ມເຫຼວ: {{ .err }}'
FileAISearchEmptyDir: 'ບໍ່ພົບໄຟລ໌ ຫຼື ໂຟນເດີພາຍໃຕ້ເສັ້ນທາງນີ້ (ຫຼື ລາຍການທັງໝົດຖືກກັ່ນກອງອອກ).'
Expand Down
1 change: 1 addition & 0 deletions agent/i18n/lang/ms.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ XfsNotFound: 'Sistem fail xfs tidak dikesan, sila pasang xfsprogs terlebih dahul
# terminal
TerminalAIBlockedRiskyCommand: 'Perintah berisiko telah disekat: {{ .command }}'
TerminalAIThinking: 'AI sedang berfikir...'
TerminalOutputTruncated: '[output dipotong, hanya output terkini dipaparkan]'
TerminalAIReadyToExecute: 'Pemikiran selesai, tekan Enter untuk jalankan (tempoh: {{ .duration }}, token: {{ .tokens }})'
TerminalAIRequestFailed: 'Permintaan AI gagal: {{ .err }}'

Expand Down
1 change: 1 addition & 0 deletions agent/i18n/lang/pt-BR.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ XfsNotFound: 'Sistema de arquivos xfs não detectado instale xfsprogs primeiro'
# terminal
TerminalAIBlockedRiskyCommand: 'Comando de risco bloqueado: {{ .command }}'
TerminalAIThinking: 'A IA está pensando...'
TerminalOutputTruncated: '[saída truncada, mostrando apenas a saída recente]'
TerminalAIReadyToExecute: 'Pensamento concluído, pressione Enter para executar (duração: {{ .duration }}, token: {{ .tokens }})'
TerminalAIRequestFailed: 'Falha na solicitação de AI: {{ .err }}'

Expand Down
1 change: 1 addition & 0 deletions agent/i18n/lang/ru.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ XfsNotFound: 'Файловая система xfs не обнаружена, с
# терминал
TerminalAIBlockedRiskyCommand: 'Опасная команда заблокирована: {{ .command }}'
TerminalAIThinking: 'AI думает...'
TerminalOutputTruncated: '[вывод усечён, показан только недавний вывод]'
TerminalAIReadyToExecute: 'Обдумывание завершено, нажмите Enter для выполнения (время: {{ .duration }}, token: {{ .tokens }})'
TerminalAIRequestFailed: 'Ошибка запроса AI: {{ .err }}'

Expand Down
1 change: 1 addition & 0 deletions agent/i18n/lang/tr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ XfsNotFound: 'XFS dosya sistemi algılanmadı, lütfen önce xfsprogs''i yükley
# terminal
TerminalAIBlockedRiskyCommand: 'Riskli komut engellendi: {{ .command }}'
TerminalAIThinking: 'AI dusunuyor...'
TerminalOutputTruncated: '[çıktı kısaltıldı, yalnızca son çıktı gösteriliyor]'
TerminalAIReadyToExecute: 'Dusunme tamamlandi, calistirmak icin Enter tusuna basin (sure: {{ .duration }}, token: {{ .tokens }})'
TerminalAIRequestFailed: 'AI istegi basarisiz oldu: {{ .err }}'

Expand Down
1 change: 1 addition & 0 deletions agent/i18n/lang/zh-Hant.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ XfsNotFound: '未偵測到 xfs 檔案系統,請先安裝 xfsprogs'
# 終端
TerminalAIBlockedRiskyCommand: '已攔截風險命令:{{ .command }}'
TerminalAIThinking: 'AI 正在思考...'
TerminalOutputTruncated: '[輸出已截斷,僅顯示最近輸出]'
TerminalAIReadyToExecute: '思考完成,請按 Enter 執行(耗時 {{ .duration }},token:{{ .tokens }})'
TerminalAIRequestFailed: 'AI 請求失敗:{{ .err }}'

Expand Down
1 change: 1 addition & 0 deletions agent/i18n/lang/zh.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ XfsNotFound: "未检测到 xfs 文件系统,请先安装 xfsprogs"
# 终端
TerminalAIBlockedRiskyCommand: "已拦截风险命令:{{ .command }}"
TerminalAIThinking: "AI 正在思考..."
TerminalOutputTruncated: "[输出已截断,仅显示最近输出]"
TerminalAIReadyToExecute: "思考完成,请回车执行(耗时 {{ .duration }},token:{{ .tokens }})"
TerminalAIRequestFailed: "AI 请求失败:{{ .err }}"

Expand Down
3 changes: 3 additions & 0 deletions agent/router/ro_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ func (s *HostRouter) InitRouter(Router *gin.RouterGroup) {
hostRouter.GET("/terminal/local", baseApi.WsLocalTerminal)
hostRouter.GET("/terminal/ssh", baseApi.WsHostSSH)
hostRouter.GET("/terminal/container", baseApi.WsContainerTerminal)
hostRouter.POST("/terminal/sessions/search", baseApi.SearchTerminalSessions)
hostRouter.POST("/terminal/sessions/close", baseApi.CloseTerminalSession)
hostRouter.POST("/terminal/sessions/closeAll", baseApi.CloseAllTerminalSessions)

hostRouter.GET("/disks", baseApi.GetCompleteDiskInfo)
hostRouter.POST("/disks/partition", baseApi.PartitionDisk)
Expand Down
Loading