859640d814
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/claude-agent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
156 lines
3.3 KiB
Go
156 lines
3.3 KiB
Go
package embedded
|
|
|
|
import (
|
|
"archive/tar"
|
|
"compress/gzip"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
const cacheDir = ".cache/anthropic-proxy/bin"
|
|
|
|
var downloads = map[string]struct {
|
|
urlTemplate string
|
|
version string
|
|
extractName string
|
|
}{
|
|
"victoria-metrics": {
|
|
urlTemplate: "https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v%s/victoria-metrics-%s-v%s.tar.gz",
|
|
version: "1.118.0",
|
|
extractName: "victoria-metrics-prod",
|
|
},
|
|
"perses": {
|
|
urlTemplate: "https://github.com/perses/perses/releases/download/v%s/perses_%s_%s_%s.tar.gz",
|
|
version: "0.53.1",
|
|
},
|
|
}
|
|
|
|
func ensureBinary(name, configPath, configBinDir string) (string, error) {
|
|
if configPath != "" {
|
|
if p, err := exec.LookPath(configPath); err == nil {
|
|
return p, nil
|
|
}
|
|
}
|
|
|
|
if p, err := exec.LookPath(name); err == nil {
|
|
return p, nil
|
|
}
|
|
|
|
binDir := configBinDir
|
|
if binDir == "" {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return "", fmt.Errorf("get home dir: %w", err)
|
|
}
|
|
binDir = filepath.Join(home, cacheDir)
|
|
}
|
|
cachedPath := filepath.Join(binDir, name)
|
|
|
|
if _, err := os.Stat(cachedPath); err == nil {
|
|
return cachedPath, nil
|
|
}
|
|
|
|
log.Info().Str("binary", name).Msg("downloading binary (first run)")
|
|
|
|
if err := os.MkdirAll(binDir, 0o755); err != nil {
|
|
return "", fmt.Errorf("create cache dir: %w", err)
|
|
}
|
|
|
|
url, err := downloadURL(name)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err := extractAll(url, binDir); err != nil {
|
|
return "", fmt.Errorf("download %s: %w", name, err)
|
|
}
|
|
|
|
d := downloads[name]
|
|
if d.extractName != "" {
|
|
oldPath := filepath.Join(binDir, d.extractName)
|
|
if _, err := os.Stat(oldPath); err == nil {
|
|
os.Rename(oldPath, cachedPath)
|
|
}
|
|
}
|
|
|
|
if _, err := os.Stat(cachedPath); err != nil {
|
|
return "", fmt.Errorf("binary %s not found after extraction", name)
|
|
}
|
|
|
|
log.Info().Str("binary", name).Str("path", cachedPath).Msg("binary downloaded")
|
|
return cachedPath, nil
|
|
}
|
|
|
|
func downloadURL(name string) (string, error) {
|
|
goarch := runtime.GOARCH
|
|
goos := runtime.GOOS
|
|
|
|
d, ok := downloads[name]
|
|
if !ok {
|
|
return "", fmt.Errorf("unknown binary: %s", name)
|
|
}
|
|
|
|
switch name {
|
|
case "victoria-metrics":
|
|
vmOS := fmt.Sprintf("%s-%s", goos, goarch)
|
|
return fmt.Sprintf(d.urlTemplate, d.version, vmOS, d.version), nil
|
|
case "perses":
|
|
return fmt.Sprintf(d.urlTemplate, d.version, d.version, goos, goarch), nil
|
|
}
|
|
return "", fmt.Errorf("unknown binary: %s", name)
|
|
}
|
|
|
|
func extractAll(url, destDir string) error {
|
|
resp, err := http.Get(url)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return fmt.Errorf("download failed: HTTP %d from %s", resp.StatusCode, url)
|
|
}
|
|
|
|
gz, err := gzip.NewReader(resp.Body)
|
|
if err != nil {
|
|
return fmt.Errorf("gzip reader: %w", err)
|
|
}
|
|
defer gz.Close()
|
|
|
|
tr := tar.NewReader(gz)
|
|
for {
|
|
hdr, err := tr.Next()
|
|
if err == io.EOF {
|
|
return nil
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("read tar: %w", err)
|
|
}
|
|
|
|
target := filepath.Join(destDir, hdr.Name)
|
|
switch hdr.Typeflag {
|
|
case tar.TypeDir:
|
|
os.MkdirAll(target, 0o755)
|
|
case tar.TypeReg:
|
|
os.MkdirAll(filepath.Dir(target), 0o755)
|
|
mode := os.FileMode(hdr.Mode)
|
|
if mode == 0 {
|
|
mode = 0o644
|
|
}
|
|
out, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
io.Copy(out, tr)
|
|
out.Close()
|
|
}
|
|
}
|
|
}
|