package server import ( "encoding/json" "errors" "fmt" "log" "net" "os" "os/exec" "os/signal" "path/filepath" "syscall" "github.com/adrg/xdg" ) var ( Socket = filepath.Join(xdg.RuntimeDir, "xfts") Thumbnails = filepath.Join(xdg.CacheHome, "thumbnails") ) type Request struct { Source string `json:"src"` Destination string `json:"dst"` } func Serve() error { listener, err := net.Listen("unix", Socket) if err != nil { return err } defer listener.Close() log.Printf("Listening on %s", Socket) c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c listener.Close() }() for { conn, err := listener.Accept() if err != nil { if errors.Is(err, net.ErrClosed) { break } log.Printf("connection: %s", err) continue } go func() { defer conn.Close() if err := handle(conn); err != nil { _, err := conn.Write([]byte(err.Error())) if err != nil { log.Println(err) } } }() } return errors.New("interrupted") } func handle(conn net.Conn) error { var req Request if err := json.NewDecoder(conn).Decode(&req); err != nil { return err } var cmd *exec.Cmd ext := filepath.Ext(req.Source) if ext == "" { return nil } switch ext { case ".png", ".jpg", ".jpeg", ".jpe", ".JPG", ".gif", ".xpm", ".xbm", ".ppm", ".mp4", ".3gp", ".svg", ".webp": cmd = exec.Command("convert", req.Source+"[0]", "-background", "#171717", "-flatten", "-define", "filename:literal=true", "-format", "ppm", "-auto-orient", "-thumbnail", "64x64", req.Destination, ) } if cmd == nil { return fmt.Errorf("unhandled type: %s", ext) } log.Println(cmd) if err := os.MkdirAll(filepath.Base(req.Destination), 0o755); err != nil { os.Remove(req.Destination) return err } if err := cmd.Run(); err != nil { os.Remove(req.Destination) return err } return nil }