diff --git a/internal/api/v1/docker/utils.go b/internal/api/v1/docker/utils.go index b74d2195..4b80e27c 100644 --- a/internal/api/v1/docker/utils.go +++ b/internal/api/v1/docker/utils.go @@ -6,9 +6,7 @@ import ( "time" "github.com/gin-gonic/gin" - "github.com/yusing/godoxy/agent/pkg/agent" apitypes "github.com/yusing/godoxy/internal/api/types" - config "github.com/yusing/godoxy/internal/config/types" "github.com/yusing/godoxy/internal/docker" gperr "github.com/yusing/goutils/errs" "github.com/yusing/goutils/http/httpheaders" @@ -22,67 +20,6 @@ type ( } ) -// getDockerClients returns a map of docker clients for the current config. -// -// Returns a map of docker clients by server name and an error if any. -// -// Even if there are errors, the map of docker clients might not be empty. -func getDockerClients() (DockerClients, gperr.Error) { - cfg := config.GetInstance() - - dockerHosts := cfg.Value().Providers.Docker - dockerClients := make(DockerClients) - - connErrs := gperr.NewBuilder("failed to connect to docker") - - for name, host := range dockerHosts { - dockerClient, err := docker.NewClient(host) - if err != nil { - connErrs.Add(err) - continue - } - dockerClients[name] = dockerClient - } - - for _, agent := range agent.ListAgents() { - dockerClient, err := docker.NewClient(agent.FakeDockerHost()) - if err != nil { - connErrs.Add(err) - continue - } - dockerClients[agent.Name] = dockerClient - } - - return dockerClients, connErrs.Error() -} - -func getDockerClient(server string) (*docker.SharedClient, bool, error) { - cfg := config.GetInstance() - var host string - for name, h := range cfg.Value().Providers.Docker { - if name == server { - host = h - break - } - } - if host == "" { - for _, agent := range agent.ListAgents() { - if agent.Name == server { - host = agent.FakeDockerHost() - break - } - } - } - if host == "" { - return nil, false, nil - } - dockerClient, err := docker.NewClient(host) - if err != nil { - return nil, false, err - } - return dockerClient, true, nil -} - // closeAllClients closes all docker clients after a delay. // // This is used to ensure that all docker clients are closed after the http handler returns. @@ -103,11 +40,7 @@ func handleResult[V any, T ResultType[V]](c *gin.Context, errs error, result T) } func serveHTTP[V any, T ResultType[V]](c *gin.Context, getResult func(ctx context.Context, dockerClients DockerClients) (T, gperr.Error)) { - dockerClients, err := getDockerClients() - if err != nil { - handleResult[V, T](c, err, nil) - return - } + dockerClients := docker.Clients() defer closeAllClients(dockerClients) if httpheaders.IsWebsocket(c.Request.Header) { diff --git a/internal/docker/client.go b/internal/docker/client.go index adf3928c..bd7f30a3 100644 --- a/internal/docker/client.go +++ b/internal/docker/client.go @@ -84,12 +84,23 @@ func closeTimedOutClients() { } } +// Clients return a map of currently connected clients. +// Close() must be called on all these clients after use. func Clients() map[string]*SharedClient { clientMapMu.RLock() - defer clientMapMu.RUnlock() clients := make(map[string]*SharedClient, len(clientMap)) maps.Copy(clients, clientMap) + clientMapMu.RUnlock() + + // add 1 ref count to prevent them from + // being closed before caller finished using them + for _, c := range clients { + // last Close() has been called, reset closeOn + if atomic.AddUint32(&c.refCount, 1) == 1 { + atomic.StoreInt64(&c.closedOn, 0) + } + } return clients }