mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-05 11:15:57 +00:00
broader support for SetDoNotAllowColumnSet + tests
This commit is contained in:
parent
eee508c36d
commit
08bdc5ecb4
8 changed files with 82 additions and 25 deletions
|
|
@ -288,6 +288,9 @@ func startServer(cfg *config.Config, manager *session.Manager) error {
|
|||
return fmt.Errorf("invalid port: %w", err)
|
||||
}
|
||||
|
||||
// Set the resize flag on the manager
|
||||
manager.SetDoNotAllowColumnSet(doNotAllowColumnSet)
|
||||
|
||||
// Create and configure server
|
||||
server := api.NewServer(manager, staticPath, serverPassword, portInt)
|
||||
server.SetNoSpawn(noSpawn)
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ func TestEscapeParser_Flush(t *testing.T) {
|
|||
parser := NewEscapeParser()
|
||||
|
||||
// Process data with incomplete sequence
|
||||
input := []byte("text\x1b[31") // incomplete CSI sequence
|
||||
input := []byte("text\x1b[31") // incomplete CSI sequence
|
||||
processed, _ := parser.ProcessData(input)
|
||||
|
||||
if !bytes.Equal(processed, []byte("text")) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ func TestProcessTerminatorIntegration(t *testing.T) {
|
|||
}
|
||||
|
||||
terminator := NewProcessTerminator(session)
|
||||
|
||||
|
||||
// Verify it was created with correct timeouts
|
||||
if terminator.gracefulTimeout != 3*time.Second {
|
||||
t.Errorf("Expected 3s graceful timeout, got %v", terminator.gracefulTimeout)
|
||||
|
|
@ -34,16 +34,16 @@ func TestProcessTerminatorIntegration(t *testing.T) {
|
|||
func TestCustomErrorsIntegration(t *testing.T) {
|
||||
// Test custom error types
|
||||
err := NewSessionError("test error", ErrSessionNotFound, "test-id")
|
||||
|
||||
|
||||
if err.Code != ErrSessionNotFound {
|
||||
t.Errorf("Expected code %v, got %v", ErrSessionNotFound, err.Code)
|
||||
}
|
||||
|
||||
|
||||
if !IsSessionError(err, ErrSessionNotFound) {
|
||||
t.Error("IsSessionError should return true")
|
||||
}
|
||||
|
||||
|
||||
if GetSessionID(err) != "test-id" {
|
||||
t.Errorf("Expected session ID 'test-id', got '%s'", GetSessionID(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,10 @@ import (
|
|||
)
|
||||
|
||||
type Manager struct {
|
||||
controlPath string
|
||||
runningSessions map[string]*Session
|
||||
mutex sync.RWMutex
|
||||
controlPath string
|
||||
runningSessions map[string]*Session
|
||||
mutex sync.RWMutex
|
||||
doNotAllowColumnSet bool
|
||||
}
|
||||
|
||||
func NewManager(controlPath string) *Manager {
|
||||
|
|
@ -26,12 +27,26 @@ func NewManager(controlPath string) *Manager {
|
|||
}
|
||||
}
|
||||
|
||||
// SetDoNotAllowColumnSet sets the flag to disable terminal resizing for all sessions
|
||||
func (m *Manager) SetDoNotAllowColumnSet(value bool) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
m.doNotAllowColumnSet = value
|
||||
}
|
||||
|
||||
// GetDoNotAllowColumnSet returns the current value of the resize disable flag
|
||||
func (m *Manager) GetDoNotAllowColumnSet() bool {
|
||||
m.mutex.RLock()
|
||||
defer m.mutex.RUnlock()
|
||||
return m.doNotAllowColumnSet
|
||||
}
|
||||
|
||||
func (m *Manager) CreateSession(config Config) (*Session, error) {
|
||||
if err := os.MkdirAll(m.controlPath, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create control directory: %w", err)
|
||||
}
|
||||
|
||||
session, err := newSession(m.controlPath, config)
|
||||
session, err := newSession(m.controlPath, config, m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -56,7 +71,7 @@ func (m *Manager) CreateSessionWithID(id string, config Config) (*Session, error
|
|||
return nil, fmt.Errorf("failed to create control directory: %w", err)
|
||||
}
|
||||
|
||||
session, err := newSessionWithID(m.controlPath, id, config)
|
||||
session, err := newSessionWithID(m.controlPath, id, config, m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -86,7 +101,7 @@ func (m *Manager) GetSession(id string) (*Session, error) {
|
|||
m.mutex.RUnlock()
|
||||
|
||||
// Fall back to loading from disk (for sessions that might have been started before this manager instance)
|
||||
return loadSession(m.controlPath, id)
|
||||
return loadSession(m.controlPath, id, m)
|
||||
}
|
||||
|
||||
func (m *Manager) FindSession(nameOrID string) (*Session, error) {
|
||||
|
|
@ -119,7 +134,7 @@ func (m *Manager) ListSessions() ([]*Info, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
session, err := loadSession(m.controlPath, entry.Name())
|
||||
session, err := loadSession(m.controlPath, entry.Name(), m)
|
||||
if err != nil {
|
||||
// Log the error when we can't load a session
|
||||
if os.Getenv("VIBETUNNEL_DEBUG") != "" {
|
||||
|
|
|
|||
|
|
@ -257,6 +257,12 @@ func (p *PTY) Run() error {
|
|||
// Handle SIGWINCH in a separate goroutine
|
||||
go func() {
|
||||
for range winchCh {
|
||||
// Check if resizing is disabled globally
|
||||
if p.session.manager != nil && p.session.manager.GetDoNotAllowColumnSet() {
|
||||
debugLog("[DEBUG] PTY.Run: Received SIGWINCH but resizing is disabled by server configuration")
|
||||
continue
|
||||
}
|
||||
|
||||
// Get current terminal size if we're attached to a terminal
|
||||
if term.IsTerminal(int(os.Stdin.Fd())) {
|
||||
width, height, err := term.GetSize(int(os.Stdin.Fd()))
|
||||
|
|
@ -434,6 +440,11 @@ func (p *PTY) Attach() error {
|
|||
signal.Notify(ch, syscall.SIGWINCH)
|
||||
go func() {
|
||||
for range ch {
|
||||
// Check if resizing is disabled globally
|
||||
if p.session.manager != nil && p.session.manager.GetDoNotAllowColumnSet() {
|
||||
debugLog("[DEBUG] PTY.Attach: Received SIGWINCH but resizing is disabled by server configuration")
|
||||
continue
|
||||
}
|
||||
if err := p.updateSize(); err != nil {
|
||||
log.Printf("[ERROR] PTY.Attach: Failed to update size: %v", err)
|
||||
}
|
||||
|
|
@ -441,8 +452,13 @@ func (p *PTY) Attach() error {
|
|||
}()
|
||||
defer signal.Stop(ch)
|
||||
|
||||
if err := p.updateSize(); err != nil {
|
||||
log.Printf("[ERROR] PTY.Attach: Failed to update initial size: %v", err)
|
||||
// Only update size initially if resizing is allowed
|
||||
if p.session.manager == nil || !p.session.manager.GetDoNotAllowColumnSet() {
|
||||
if err := p.updateSize(); err != nil {
|
||||
log.Printf("[ERROR] PTY.Attach: Failed to update initial size: %v", err)
|
||||
}
|
||||
} else {
|
||||
debugLog("[DEBUG] PTY.Attach: Skipping initial resize - resizing is disabled by server configuration")
|
||||
}
|
||||
|
||||
errCh := make(chan error, 2)
|
||||
|
|
|
|||
|
|
@ -67,14 +67,15 @@ type Session struct {
|
|||
stdinPipe *os.File
|
||||
stdinMutex sync.Mutex
|
||||
mu sync.RWMutex
|
||||
manager *Manager // Reference to manager for accessing global settings
|
||||
}
|
||||
|
||||
func newSession(controlPath string, config Config) (*Session, error) {
|
||||
func newSession(controlPath string, config Config, manager *Manager) (*Session, error) {
|
||||
id := uuid.New().String()
|
||||
return newSessionWithID(controlPath, id, config)
|
||||
return newSessionWithID(controlPath, id, config, manager)
|
||||
}
|
||||
|
||||
func newSessionWithID(controlPath string, id string, config Config) (*Session, error) {
|
||||
func newSessionWithID(controlPath string, id string, config Config, manager *Manager) (*Session, error) {
|
||||
sessionPath := filepath.Join(controlPath, id)
|
||||
|
||||
// Only log in debug mode
|
||||
|
|
@ -159,10 +160,11 @@ func newSessionWithID(controlPath string, id string, config Config) (*Session, e
|
|||
ID: id,
|
||||
controlPath: controlPath,
|
||||
info: info,
|
||||
manager: manager,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func loadSession(controlPath, id string) (*Session, error) {
|
||||
func loadSession(controlPath, id string, manager *Manager) (*Session, error) {
|
||||
sessionPath := filepath.Join(controlPath, id)
|
||||
info, err := LoadInfo(sessionPath)
|
||||
if err != nil {
|
||||
|
|
@ -173,6 +175,7 @@ func loadSession(controlPath, id string) (*Session, error) {
|
|||
ID: id,
|
||||
controlPath: controlPath,
|
||||
info: info,
|
||||
manager: manager,
|
||||
}
|
||||
|
||||
// Validate that essential session files exist
|
||||
|
|
@ -437,8 +440,9 @@ func (s *Session) cleanup() {
|
|||
}
|
||||
|
||||
func (s *Session) Resize(width, height int) error {
|
||||
if s.pty == nil {
|
||||
return NewSessionError("session not started", ErrSessionNotRunning, s.ID)
|
||||
// Check if resizing is disabled globally
|
||||
if s.manager != nil && s.manager.GetDoNotAllowColumnSet() {
|
||||
return NewSessionError("terminal resizing is disabled by server configuration", ErrInvalidInput, s.ID)
|
||||
}
|
||||
|
||||
// Check if session is still alive
|
||||
|
|
@ -464,7 +468,20 @@ func (s *Session) Resize(width, height int) error {
|
|||
log.Printf("[ERROR] Failed to save session info after resize: %v", err)
|
||||
}
|
||||
|
||||
// Resize the PTY
|
||||
// If this is a spawned session, send resize command through control FIFO
|
||||
if s.IsSpawned() {
|
||||
cmd := &ControlCommand{
|
||||
Cmd: "resize",
|
||||
Cols: width,
|
||||
Rows: height,
|
||||
}
|
||||
return SendControlCommand(s.Path(), cmd)
|
||||
}
|
||||
|
||||
// For non-spawned sessions, resize the PTY directly
|
||||
if s.pty == nil {
|
||||
return NewSessionError("session not started", ErrSessionNotRunning, s.ID)
|
||||
}
|
||||
return s.pty.Resize(width, height)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ func TestNewSession(t *testing.T) {
|
|||
tmpDir := t.TempDir()
|
||||
controlPath := filepath.Join(tmpDir, "control")
|
||||
|
||||
// Create a test manager
|
||||
manager := NewManager(controlPath)
|
||||
|
||||
config := &Config{
|
||||
Name: "test-session",
|
||||
Cmdline: []string{"/bin/sh", "-c", "echo test"},
|
||||
|
|
@ -22,7 +25,7 @@ func TestNewSession(t *testing.T) {
|
|||
Height: 24,
|
||||
}
|
||||
|
||||
session, err := newSession(controlPath, *config)
|
||||
session, err := newSession(controlPath, *config, manager)
|
||||
if err != nil {
|
||||
t.Fatalf("newSession() error = %v", err)
|
||||
}
|
||||
|
|
@ -60,10 +63,13 @@ func TestNewSession_Defaults(t *testing.T) {
|
|||
tmpDir := t.TempDir()
|
||||
controlPath := filepath.Join(tmpDir, "control")
|
||||
|
||||
// Create a test manager
|
||||
manager := NewManager(controlPath)
|
||||
|
||||
// Minimal config
|
||||
config := &Config{}
|
||||
|
||||
session, err := newSession(controlPath, *config)
|
||||
session, err := newSession(controlPath, *config, manager)
|
||||
if err != nil {
|
||||
t.Fatalf("newSession() error = %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,4 +73,4 @@ func TestIsTerminal(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue