diff --git a/internal/extensions/downloader.go b/internal/extensions/downloader.go new file mode 100644 index 0000000..dc3f74c --- /dev/null +++ b/internal/extensions/downloader.go @@ -0,0 +1,68 @@ +package extensions + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "time" +) + +type Downloader interface { + Download(ctx context.Context, dest string) error +} + +func NewDownloader(downloadLink *registryExtensionDownloadLink) (Downloader, error) { + switch downloadLink.Provider { + case "github-release": + return newGitHubReleaseDownloader(downloadLink), nil + default: + return nil, fmt.Errorf("invalid provider type: %s", downloadLink.Provider) + } +} + +type gitHubReleaseDownloader struct { + link *registryExtensionDownloadLink +} + +func newGitHubReleaseDownloader(downloadLink *registryExtensionDownloadLink) Downloader { + return &gitHubReleaseDownloader{ + link: downloadLink, + } +} + +func (d *gitHubReleaseDownloader) Download(ctx context.Context, dest string) error { + client := http.DefaultClient + + client.Timeout = time.Second * 60 + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, d.link.Url, nil) + if err != nil { + return err + } + + if accessToken := os.Getenv("SHUTTLE_EXTENSIONS_GITHUB_ACCESS_TOKEN"); accessToken != "" { + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken)) + } else if accessToken := os.Getenv("GITHUB_ACCESS_TOKEN"); accessToken != "" { + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken)) + } + + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + extensionBinary, err := os.Create(dest) + if err != nil { + return err + } + defer extensionBinary.Close() + + if _, err := io.Copy(extensionBinary, resp.Body); err != nil { + return err + } + + return nil +} diff --git a/internal/extensions/extension.go b/internal/extensions/extension.go index c7afee5..ff8cb79 100644 --- a/internal/extensions/extension.go +++ b/internal/extensions/extension.go @@ -43,9 +43,16 @@ func (e *Extension) Ensure(ctx context.Context) error { return fmt.Errorf("failed to find a valid extension matching your os and architecture") } - //TODO: Initiate download + downloader, err := NewDownloader(downloadLink) + if err != nil { + return err + } + + if err := downloader.Download(ctx, binaryPath); err != nil { + return err + } - panic("not implemented yet") + return nil } func (e *Extension) getExtensionBinaryName() string { diff --git a/internal/extensions/registry_index.go b/internal/extensions/registry_index.go index e5db77a..ea33de3 100644 --- a/internal/extensions/registry_index.go +++ b/internal/extensions/registry_index.go @@ -19,6 +19,7 @@ type ( Os string `json:"os"` Url string `json:"url"` Checksum string `json:"checksum"` + Provider string `json:"provider"` } registryExtension struct {