From 671f7815646747a0dbc3b1e8aded7debb8b36f4a Mon Sep 17 00:00:00 2001 From: ssongliu Date: Tue, 8 Sep 2026 16:58:54 +0800 Subject: [PATCH] feat: add terminal session rules hint (#13744) --- agent/utils/terminal/registry.go | 47 +- agent/utils/terminal/session.go | 11 +- .../src/components/terminal/dock/index.vue | 192 ++++++-- frontend/src/components/terminal/index.vue | 28 +- frontend/src/lang/modules/en.ts | 7 + frontend/src/lang/modules/es-es.ts | 9 + frontend/src/lang/modules/fa.ts | 7 + frontend/src/lang/modules/ja.ts | 7 + frontend/src/lang/modules/ko.ts | 7 + frontend/src/lang/modules/lo.ts | 7 + frontend/src/lang/modules/ms.ts | 9 + frontend/src/lang/modules/pt-br.ts | 7 + frontend/src/lang/modules/ru.ts | 8 + frontend/src/lang/modules/tr.ts | 8 + frontend/src/lang/modules/zh-Hant.ts | 6 + frontend/src/lang/modules/zh.ts | 6 + .../src/views/terminal/terminal/index.vue | 428 +++++++++++------- 17 files changed, 532 insertions(+), 262 deletions(-) diff --git a/agent/utils/terminal/registry.go b/agent/utils/terminal/registry.go index f3103bf28..15443a03f 100644 --- a/agent/utils/terminal/registry.go +++ b/agent/utils/terminal/registry.go @@ -2,7 +2,6 @@ package terminal import ( "errors" - "fmt" "sort" "sync" ) @@ -11,13 +10,6 @@ import ( // Open stores, Close deletes. var sessions sync.Map -const maxSessionsPerIdentity = 10 - -var ( - sessionSlotsMu sync.Mutex - sessionSlots = make(map[Identity]int) -) - var errSessionNotFound = errors.New("terminal session not found") const ( @@ -34,47 +26,12 @@ func (i Identity) Valid() bool { return i.UserID != "" && i.AuthSessionID != "" } -func reserveSessionSlot(identity Identity) error { - if !identity.Valid() { - return errors.New("missing terminal identity") - } - sessionSlotsMu.Lock() - defer sessionSlotsMu.Unlock() - if sessionSlots[identity] >= maxSessionsPerIdentity { - return fmt.Errorf("terminal session limit reached (maximum %d)", maxSessionsPerIdentity) - } - sessionSlots[identity]++ - return nil -} - -func releaseSessionSlot(identity Identity) { - sessionSlotsMu.Lock() - defer sessionSlotsMu.Unlock() - releaseSessionSlotLocked(identity) -} - -func releaseSessionSlotLocked(identity Identity) { - remaining := sessionSlots[identity] - 1 - if remaining <= 0 { - delete(sessionSlots, identity) - return - } - sessionSlots[identity] = remaining -} - -func registerReservedSession(s *Session) { +func registerSession(s *Session) { sessions.Store(s.ID, s) } func unregisterSession(s *Session) { - sessionSlotsMu.Lock() - defer sessionSlotsMu.Unlock() - current, ok := sessions.Load(s.ID) - if !ok || current != s { - return - } - sessions.Delete(s.ID) - releaseSessionSlotLocked(Identity{UserID: s.UserID, AuthSessionID: s.AuthSessionID}) + sessions.CompareAndDelete(s.ID, s) } func Lookup(id string, identity Identity) (*Session, bool) { diff --git a/agent/utils/terminal/session.go b/agent/utils/terminal/session.go index 8e8bf532f..00f69ffde 100644 --- a/agent/utils/terminal/session.go +++ b/agent/utils/terminal/session.go @@ -37,7 +37,7 @@ const ( CloseCodeSessionNotFound = 4404 // CloseCodeAttachedElsewhere: a newer websocket took over the session. CloseCodeAttachedElsewhere = 4409 - CloseCodeRevalidate = 4410 + CloseCodeRevalidate = 4410 ) var errSessionClosed = errors.New("terminal session is closed") @@ -169,13 +169,9 @@ func Open(client *gossh.Client, opts SessionOptions) (*Session, error) { if err := validateSessionOptions(opts); err != nil { return nil, err } - if err := reserveSessionSlot(opts.Identity); err != nil { - return nil, err - } ring := newRingBuffer() backend, err := newSSHBackend(client, opts.Cols, opts.Rows, opts.InitCmd, ring) if err != nil { - releaseSessionSlot(opts.Identity) return nil, err } return openBackend(backend, ring, opts), nil @@ -188,9 +184,6 @@ func OpenCommand(command *LocalCommand, opts SessionOptions) (*Session, error) { if command == nil { return nil, errors.New("nil terminal command") } - if err := reserveSessionSlot(opts.Identity); err != nil { - return nil, err - } ring := newRingBuffer() return openBackend(newCommandBackend(command, ring), ring, opts), nil } @@ -216,7 +209,7 @@ func openBackend(backend sessionBackend, ring *ringBuffer, opts SessionOptions) done: make(chan struct{}), } s.closeFn = sync.OnceFunc(s.doClose) - registerReservedSession(s) + registerSession(s) go s.pump() go s.keepaliveLoop() go s.waitBackend() diff --git a/frontend/src/components/terminal/dock/index.vue b/frontend/src/components/terminal/dock/index.vue index bd1017937..ddc994d4f 100644 --- a/frontend/src/components/terminal/dock/index.vue +++ b/frontend/src/components/terminal/dock/index.vue @@ -23,7 +23,21 @@