yao/sandbox/ipc/manager.go

100 lines
2.2 KiB
Go

package ipc
import (
"context"
"fmt"
"net"
"os"
"path/filepath"
"sync"
)
// Manager manages IPC sessions
type Manager struct {
sessions sync.Map // sessionID → *Session
sockDir string // Socket directory
}
// NewManager creates a new IPC manager
func NewManager(sockDir string) *Manager {
return &Manager{
sockDir: sockDir,
}
}
// Create creates a new IPC session
func (m *Manager) Create(ctx context.Context, sessionID string, agentCtx *AgentContext, mcpTools map[string]*MCPTool) (*Session, error) {
// Close existing session if any
m.Close(sessionID)
// Create socket path
socketPath := filepath.Join(m.sockDir, sessionID+".sock")
// Ensure directory exists
if err := os.MkdirAll(m.sockDir, 0755); err != nil {
return nil, fmt.Errorf("failed to create socket directory: %w", err)
}
// Remove existing socket file if any
os.Remove(socketPath)
// Create Unix socket listener
listener, err := net.Listen("unix", socketPath)
if err != nil {
return nil, fmt.Errorf("failed to create Unix socket: %w", err)
}
// Set socket permissions (readable/writable by owner and group)
if err := os.Chmod(socketPath, 0660); err != nil {
listener.Close()
os.Remove(socketPath)
return nil, fmt.Errorf("failed to set socket permissions: %w", err)
}
// Create cancellable context
sessionCtx, cancel := context.WithCancel(ctx)
session := &Session{
ID: sessionID,
SocketPath: socketPath,
Listener: listener,
Context: agentCtx,
MCPTools: mcpTools,
cancel: cancel,
}
// Start serving in background
go session.serve(sessionCtx)
// Store session
m.sessions.Store(sessionID, session)
return session, nil
}
// Close closes an IPC session
func (m *Manager) Close(sessionID string) error {
if s, ok := m.sessions.LoadAndDelete(sessionID); ok {
session := s.(*Session)
return session.Close()
}
return nil
}
// Get returns an existing session
func (m *Manager) Get(sessionID string) (*Session, bool) {
if s, ok := m.sessions.Load(sessionID); ok {
return s.(*Session), true
}
return nil, false
}
// CloseAll closes all sessions
func (m *Manager) CloseAll() {
m.sessions.Range(func(key, value interface{}) bool {
session := value.(*Session)
session.Close()
m.sessions.Delete(key)
return true
})
}