github.com/artpar/rclone@v1.67.3/cmd/serve/docker/serve.go (about)

     1  package docker
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"fmt"
     7  	"net"
     8  	"net/http"
     9  	"os"
    10  	"path/filepath"
    11  	"runtime"
    12  
    13  	"github.com/artpar/rclone/fs"
    14  	"github.com/artpar/rclone/lib/atexit"
    15  	"github.com/artpar/rclone/lib/file"
    16  )
    17  
    18  // Server connects plugin with docker daemon by protocol
    19  type Server http.Server
    20  
    21  // NewServer creates new docker plugin server
    22  func NewServer(drv *Driver) *Server {
    23  	return &Server{Handler: newRouter(drv)}
    24  }
    25  
    26  // Shutdown the server
    27  func (s *Server) Shutdown(ctx context.Context) error {
    28  	hs := (*http.Server)(s)
    29  	return hs.Shutdown(ctx)
    30  }
    31  
    32  func (s *Server) serve(listener net.Listener, addr, tempFile string) error {
    33  	if tempFile != "" {
    34  		atexit.Register(func() {
    35  			// remove spec file or self-created unix socket
    36  			fs.Debugf(nil, "Removing stale file %s", tempFile)
    37  			_ = os.Remove(tempFile)
    38  		})
    39  	}
    40  	hs := (*http.Server)(s)
    41  	return hs.Serve(listener)
    42  }
    43  
    44  // ServeUnix makes the handler to listen for requests in a unix socket.
    45  // It also creates the socket file in the right directory for docker to read.
    46  func (s *Server) ServeUnix(path string, gid int) error {
    47  	listener, socketPath, err := newUnixListener(path, gid)
    48  	if err != nil {
    49  		return err
    50  	}
    51  	if socketPath != "" {
    52  		path = socketPath
    53  		fs.Infof(nil, "Serving unix socket: %s", path)
    54  	} else {
    55  		fs.Infof(nil, "Serving systemd socket")
    56  	}
    57  	return s.serve(listener, path, socketPath)
    58  }
    59  
    60  // ServeTCP makes the handler listen for request on a given TCP address.
    61  // It also writes the spec file in the right directory for docker to read.
    62  func (s *Server) ServeTCP(addr, specDir string, tlsConfig *tls.Config, noSpec bool) error {
    63  	listener, err := net.Listen("tcp", addr)
    64  	if err != nil {
    65  		return err
    66  	}
    67  	if tlsConfig != nil {
    68  		tlsConfig.NextProtos = []string{"http/1.1"}
    69  		listener = tls.NewListener(listener, tlsConfig)
    70  	}
    71  	addr = listener.Addr().String()
    72  	specFile := ""
    73  	if !noSpec {
    74  		specFile, err = writeSpecFile(addr, "tcp", specDir)
    75  		if err != nil {
    76  			return err
    77  		}
    78  	}
    79  	fs.Infof(nil, "Serving TCP socket: %s", addr)
    80  	return s.serve(listener, addr, specFile)
    81  }
    82  
    83  func writeSpecFile(addr, proto, specDir string) (string, error) {
    84  	if specDir == "" && runtime.GOOS == "windows" {
    85  		specDir = os.TempDir()
    86  	}
    87  	if specDir == "" {
    88  		specDir = defSpecDir
    89  	}
    90  	if err := file.MkdirAll(specDir, 0755); err != nil {
    91  		return "", err
    92  	}
    93  	specFile := filepath.Join(specDir, "rclone.spec")
    94  	url := fmt.Sprintf("%s://%s", proto, addr)
    95  	if err := os.WriteFile(specFile, []byte(url), 0644); err != nil {
    96  		return "", err
    97  	}
    98  	fs.Debugf(nil, "Plugin spec has been written to %s", specFile)
    99  	return specFile, nil
   100  }