commit 8161b52b1cf0926a06e9685aeaf3b808f3b098a9 Author: sewn Date: Mon Mar 18 19:45:02 2024 +0300 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a80ae9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +xftc +xfts diff --git a/README.md b/README.md new file mode 100644 index 0000000..9a4cba5 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# xfts + +Toy server-client CLI applications used to speed up [xfiles](https://github.com/phillbush/xfiles) thumbnail generation diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..3ef9c88 --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module github.com/apprehensions/xfts + +go 1.21.6 + +require github.com/adrg/xdg v0.4.0 + +require golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fccdf6c --- /dev/null +++ b/go.sum @@ -0,0 +1,14 @@ +github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= +github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 0000000..077b9dd --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,117 @@ +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 +}