// server9p.go - State management for 9P toolsrv package main import ( "crypto/rand" "encoding/hex" "fmt" "runtime" "sync" "ollie/fsedsl" ) // Server9P holds the state for the 9P tool server. type Server9P struct { mu sync.RWMutex secret string // set on first auth, verified on subsequent token string // session token returned after auth registry *Registry // tool registry sessID string // session ID for registry scoping yolo bool // skip sandbox // Process management fs *FS9P } // NewServer9P creates a new 9P tool server. func NewServer9P() *Server9P { return &Server9P{ fs: NewFS9P(""), // cwd set per-agent } } // SetRegistry configures the tool registry and session ID. func (s *Server9P) SetRegistry(r *Registry, sessID string) { s.mu.Lock() s.registry = r s.sessID = sessID s.fs.SetRegistry(r, sessID) s.mu.Unlock() } // SetYolo enables/disables sandbox bypass. func (s *Server9P) SetYolo(yolo bool) { s.mu.Lock() s.yolo = yolo s.fs.SetYolo(yolo) s.mu.Unlock() } // Authenticate handles secret verification. // First call sets the secret; subsequent calls must match it. // Returns (token, nil) on success, ("", error) on failure. func (s *Server9P) Authenticate(clientSecret string) (string, error) { s.mu.Lock() defer s.mu.Unlock() if s.secret == "" { // First auth - set the secret s.secret = clientSecret s.token = randomToken() return s.token, nil } // Subsequent auth - verify secret if clientSecret != s.secret { return "", fmt.Errorf("authentication failed") } return s.token, nil } // Token returns the current session token (empty if not authenticated). func (s *Server9P) Token() string { s.mu.RLock() defer s.mu.RUnlock() return s.token } // HostInfo returns platform info as key=value lines. func (s *Server9P) HostInfo() string { return fmt.Sprintf("platform=%s\narch=%s\n", runtime.GOOS, runtime.GOARCH) } // FS returns the underlying filesystem state. func (s *Server9P) FS() *FS9P { return s.fs } // BuildTree creates the fsedsl tree for this server. func (s *Server9P) BuildTree() *fsedsl.Tree { ctx := ToolsrvCtx{Server: s} return fsedsl.BuildTree(ToolsrvSpec(), ctx) } func randomToken() string { b := make([]byte, 16) rand.Read(b) return hex.EncodeToString(b) }