package docker import ( "context" "crypto/tls" "fmt" "net" "net/http" "os" "path/filepath" "runtime" "github.com/rclone/rclone/fs" "github.com/rclone/rclone/lib/atexit" "github.com/rclone/rclone/lib/file" ) // Server connects plugin with docker daemon by protocol type Server http.Server // NewServer creates new docker plugin server func NewServer(drv *Driver) *Server { return &Server{Handler: newRouter(drv)} } // Shutdown the server func (s *Server) Shutdown(ctx context.Context) error { hs := (*http.Server)(s) return hs.Shutdown(ctx) } func (s *Server) serve(listener net.Listener, addr, tempFile string) error { if tempFile != "" { atexit.Register(func() { // remove spec file or self-created unix socket fs.Debugf(nil, "Removing stale file %s", tempFile) _ = os.Remove(tempFile) }) } hs := (*http.Server)(s) return hs.Serve(listener) } // ServeUnix makes the handler to listen for requests in a unix socket. // It also creates the socket file in the right directory for docker to read. func (s *Server) ServeUnix(path string, gid int) error { listener, socketPath, err := newUnixListener(path, gid) if err != nil { return err } if socketPath != "" { path = socketPath fs.Infof(nil, "Serving unix socket: %s", path) } else { fs.Infof(nil, "Serving systemd socket") } return s.serve(listener, path, socketPath) } // ServeTCP makes the handler listen for request on a given TCP address. // It also writes the spec file in the right directory for docker to read. func (s *Server) ServeTCP(addr, specDir string, tlsConfig *tls.Config, noSpec bool) error { listener, err := net.Listen("tcp", addr) if err != nil { return err } if tlsConfig != nil { tlsConfig.NextProtos = []string{"http/1.1"} listener = tls.NewListener(listener, tlsConfig) } addr = listener.Addr().String() specFile := "" if !noSpec { specFile, err = writeSpecFile(addr, "tcp", specDir) if err != nil { return err } } fs.Infof(nil, "Serving TCP socket: %s", addr) return s.serve(listener, addr, specFile) } func writeSpecFile(addr, proto, specDir string) (string, error) { if specDir == "" && runtime.GOOS == "windows" { specDir = os.TempDir() } if specDir == "" { specDir = defSpecDir } if err := file.MkdirAll(specDir, 0755); err != nil { return "", err } specFile := filepath.Join(specDir, "rclone.spec") url := fmt.Sprintf("%s://%s", proto, addr) if err := os.WriteFile(specFile, []byte(url), 0644); err != nil { return "", err } fs.Debugf(nil, "Plugin spec has been written to %s", specFile) return specFile, nil }