dify/dify-agent-runtime/cmd/shellctl/main.go
Yunlu Wen 302d7b1e1b
feat(agent): shellctl rewritten in go (#38841)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-15 01:58:36 +00:00

90 lines
2.0 KiB
Go

// shellctl is the main server binary that exposes a REST API for managing
// tmux-backed shell jobs inside a sandbox container.
package main
import (
"context"
"flag"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/langgenius/dify/dify-agent-runtime/internal/server"
)
func main() {
if err := run(); err != nil {
fmt.Fprintf(os.Stderr, "shellctl: %v\n", err)
os.Exit(1)
}
}
func run() error {
// Parse CLI flags
serveCmd := flag.NewFlagSet("serve", flag.ExitOnError)
listen := serveCmd.String("listen", "", "address to listen on (host:port)")
stateDir := serveCmd.String("state-dir", "", "state directory path")
token := serveCmd.String("token", "", "bearer auth token")
if len(os.Args) < 2 || os.Args[1] != "serve" {
fmt.Fprintf(os.Stderr, "Usage: shellctl serve [flags]\n")
return nil
}
if err := serveCmd.Parse(os.Args[2:]); err != nil {
return err
}
// Build config
config := server.DefaultConfig()
if *listen != "" {
config.Listen = *listen
}
if *stateDir != "" {
config.StateDir = *stateDir
}
if *token != "" {
config.AuthToken = *token
}
// Initialize service
svc := server.NewService(config)
if err := svc.Initialize(); err != nil {
return fmt.Errorf("initialize: %w", err)
}
defer svc.Shutdown()
svc.StartBackgroundGC()
svc.StartBackgroundPipeMonitor()
// Create HTTP server
handler := server.Handler(svc, config)
srv := &http.Server{
Addr: config.Listen,
Handler: handler,
ReadTimeout: 0, // Long-poll requires no read timeout
WriteTimeout: 0,
}
// Graceful shutdown on signal
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
go func() {
<-ctx.Done()
log.Println("shutting down...")
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = srv.Shutdown(shutdownCtx)
}()
log.Printf("shellctl serving on %s", config.Listen)
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
return err
}
return nil
}