package service import ( "context" "strings" "sync" "github.com/tinyauthapp/tinyauth/internal/model" "github.com/tinyauthapp/tinyauth/internal/utils/decoders" "github.com/tinyauthapp/tinyauth/internal/utils/logger" container "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" ) type DockerService struct { log *logger.Logger client *client.Client context context.Context wg *sync.WaitGroup isConnected bool } func NewDockerService( log *logger.Logger, context context.Context, wg *sync.WaitGroup, ) *DockerService { return &DockerService{ log: log, context: context, wg: wg, } } func (docker *DockerService) Init() error { client, err := client.NewClientWithOpts(client.FromEnv) if err != nil { return err } client.NegotiateAPIVersion(docker.context) docker.client = client _, err = docker.client.Ping(docker.context) if err != nil { docker.log.App.Debug().Err(err).Msg("Docker not connected") docker.isConnected = false docker.client = nil docker.context = nil return nil } docker.isConnected = true docker.log.App.Debug().Msg("Docker connected successfully") docker.wg.Go(docker.watchAndClose) return nil } func (docker *DockerService) getContainers() ([]container.Summary, error) { return docker.client.ContainerList(docker.context, container.ListOptions{}) } func (docker *DockerService) inspectContainer(containerId string) (container.InspectResponse, error) { return docker.client.ContainerInspect(docker.context, containerId) } func (docker *DockerService) GetLabels(appDomain string) (*model.App, error) { if !docker.isConnected { docker.log.App.Debug().Msg("Docker service not connected, returning empty labels") return nil, nil } containers, err := docker.getContainers() if err != nil { return nil, err } for _, ctr := range containers { inspect, err := docker.inspectContainer(ctr.ID) if err != nil { return nil, err } labels, err := decoders.DecodeLabels[model.Apps](inspect.Config.Labels, "apps") if err != nil { return nil, err } for appName, appLabels := range labels.Apps { if appLabels.Config.Domain == appDomain { docker.log.App.Debug().Str("id", inspect.ID).Str("name", inspect.Name).Msg("Found matching container by domain") return &appLabels, nil } if strings.SplitN(appDomain, ".", 2)[0] == appName { docker.log.App.Debug().Str("id", inspect.ID).Str("name", inspect.Name).Msg("Found matching container by app name") return &appLabels, nil } } } docker.log.App.Debug().Str("domain", appDomain).Msg("No matching container found for domain") return nil, nil } func (docker *DockerService) watchAndClose() { <-docker.context.Done() docker.log.App.Debug().Msg("Closing Docker client") if docker.client != nil { err := docker.client.Close() if err != nil { docker.log.App.Error().Err(err).Msg("Error closing Docker client") } } }