Files
zeekayandHanzo Dev da299df77d the corporate name is Lux Industries Inc
Lux Partners Limited is not the entity behind this work. Every place the
old name stood — copyright lines, site footers, brand config, legal and
compliance text — now names the company that actually holds it.

lux.fund is the exception and is not renamed to match: that site belongs
to Lux Assets Management LLC, a different company, and it says so.

Two kinds of line were left for a person rather than rewritten. A dated
news item recording that Lux Partners Limited was established in the Isle
of Man is a historical fact, and renaming it would falsify the record. And
a sentence asserting that the company is domiciled in the Isle of Man is a
claim about a jurisdiction, not a name — an Inc or an LLC is not an Isle
of Man company, so swapping the name there would assert something untrue.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-28 13:05:15 -07:00

159 lines
4.7 KiB
Go

// Copyright (C) 2022, Lux Industries Inc All rights reserved.
// See the file LICENSE for licensing terms.
package application
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"github.com/luxfi/constants"
"golang.org/x/mod/semver"
)
const githubVersionTagName = "tag_name"
// Downloader is a generic interface for performing highly testable downloads. All methods here involve
// external http requests. To write tests using these functions, provide a mocked version of this
// interface to your application object.
type Downloader interface {
Download(url string) ([]byte, error)
DownloadWithTee(url string, filePath string) ([]byte, error)
GetLatestReleaseVersion(releaseURL string) (string, error)
GetLatestPreReleaseVersion(releaseURL string) (string, error)
GetAllReleasesForRepo(org, repo string) ([]string, error)
}
type downloader struct{}
func NewDownloader() Downloader {
return &downloader{}
}
func (downloader) Download(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected http status code: %d", resp.StatusCode)
}
return io.ReadAll(resp.Body)
}
// DownloadWithTee downloads a file and saves it to disk while also returning the content
func (downloader) DownloadWithTee(url string, filePath string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected http status code: %d", resp.StatusCode)
}
// Read the content
content, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// Save to file
if err := os.WriteFile(filePath, content, 0644); err != nil {
return nil, err
}
return content, nil
}
func (d downloader) GetAllReleasesForRepo(org, repo string) ([]string, error) {
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases", org, repo)
token := os.Getenv(constants.GithubAPITokenEnvVarName)
body, err := d.doAPIRequest(url, token)
if err != nil {
return nil, err
}
defer body.Close()
jsonBytes, err := io.ReadAll(body)
if err != nil {
return nil, fmt.Errorf("failed to get latest binary version from %s: %w", url, err)
}
var releaseArr []map[string]interface{}
if err := json.Unmarshal(jsonBytes, &releaseArr); err != nil {
return nil, fmt.Errorf("failed to unmarshal binary json version string: %w", err)
}
releases := make([]string, len(releaseArr))
for i, r := range releaseArr {
version := r[githubVersionTagName].(string)
if !semver.IsValid(version) {
return nil, fmt.Errorf("invalid version string: %s", version)
}
releases[i] = version
}
return releases, nil
}
func (downloader) doAPIRequest(url, token string) (io.ReadCloser, error) {
request, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request for %s: %w", url, err)
}
if token != "" {
// avoid rate limitation issues at CI
request.Header.Set("authorization", fmt.Sprintf("Bearer %s", token))
}
resp, err := http.DefaultClient.Do(request)
if err != nil {
return nil, fmt.Errorf("failed doing request to %s: %w", url, err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed doing request %s: unexpected http status code: %d", url, resp.StatusCode)
}
return resp.Body, nil
}
// GetLatestReleaseVersion returns the latest available version from github
func (d downloader) GetLatestReleaseVersion(releaseURL string) (string, error) {
// TODO: Question if there is a less error prone (= simpler) way to install latest node
// Maybe the binary package manager should also allow the actual node binary for download
token := os.Getenv(constants.GithubAPITokenEnvVarName)
body, err := d.doAPIRequest(releaseURL, token)
if err != nil {
return "", err
}
defer body.Close()
jsonBytes, err := io.ReadAll(body)
if err != nil {
return "", fmt.Errorf("failed to get latest binary version from %s: %w", releaseURL, err)
}
var jsonStr map[string]interface{}
if err := json.Unmarshal(jsonBytes, &jsonStr); err != nil {
return "", fmt.Errorf("failed to unmarshal binary json version string: %w", err)
}
version := jsonStr[githubVersionTagName].(string)
if !semver.IsValid(version) {
return "", fmt.Errorf("invalid version string: %s", version)
}
return version, nil
}
// GetLatestPreReleaseVersion returns the latest pre-release version from github
func (d downloader) GetLatestPreReleaseVersion(releaseURL string) (string, error) {
// For now, just return the latest release version
// This can be enhanced later to specifically look for pre-releases
return d.GetLatestReleaseVersion(releaseURL)
}