package api import ( "bufio" "context" "fmt" "io" "log/slog" "regexp" "time" "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" ) const vttContainerId string = "foundry-foundry-1" // Strip ansi control characters from source // // The source reader is automatically closed when stripped reader is func StripAnsi(source io.ReadCloser) io.ReadCloser { regex := regexp.MustCompile(`\x1b[[0-9;]*m`) reader, writer := io.Pipe() go func() { bufReader := bufio.NewReader(source) defer source.Close() defer writer.Close() cleanSource: for { line, err := bufReader.ReadBytes('\n') switch { case err == io.EOF: if len(line) > 0 { cleaned := regex.ReplaceAll(line, []byte("")) writer.Write(cleaned) } break cleanSource case err != nil: panic(err) default: cleaned := regex.ReplaceAll(line, []byte("")) writer.Write(cleaned) } } }() return reader } func stopVtt(ctx context.Context) error { apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { Logger.ErrorContext(ctx, "Failed to get docker api client", slog.Any("err", err)) return err } Logger.InfoContext(ctx, "Stopping foundry container") err = apiClient.ContainerStop(ctx, vttContainerId, container.StopOptions{}) if err != nil { Logger.ErrorContext(ctx, "Error occured while stopping foundry container", slog.Any("err", err)) return err } return nil } // Get readcloser for logs // If lines is zero, returns all logs. func vttLogs(ctx context.Context, lines uint) (io.ReadCloser, error) { apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { Logger.ErrorContext(ctx, "Failed to get docker api client", slog.Any("err", err)) return nil, err } opts := container.LogsOptions{ ShowStdout: true, ShowStderr: true, } if lines != 0 { opts.Tail = fmt.Sprint(lines) } Logger.DebugContext(ctx, "Getting container logs") r, err := apiClient.ContainerLogs(ctx, vttContainerId, opts) if err != nil { Logger.ErrorContext(ctx, "Failed to get foundry container's logs", slog.Any("err", err)) return nil, err } return StripAnsi(r), nil } func vttStatus(ctx context.Context) ServerStatus { status := ServerStatus{} status.Site = VTT_URL status.Timestamp = time.Now() apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { Logger.ErrorContext(ctx, "Failed to get docker api client", slog.Any("err", err)) return status } json, err := apiClient.ContainerInspect(ctx, vttContainerId) if err != nil { Logger.ErrorContext(ctx, "Error occured while geting foundry container stats", slog.Any("err", err)) return status } status.Online = json.State.Running return status }