mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-09-26 19:31:17 +08:00
257 lines
7.6 KiB
Go
257 lines
7.6 KiB
Go
package util
|
|
|
|
import (
|
|
"archive/zip"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/schollz/progressbar/v3"
|
|
log "github.com/sirupsen/logrus"
|
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
|
)
|
|
|
|
var (
|
|
address = []string{
|
|
"https://api.github.com/repos/kubenetworks/kubevpn/releases/latest",
|
|
"https://api.github.com/repos/wencaiwulue/kubevpn/releases/latest",
|
|
}
|
|
)
|
|
|
|
func GetManifest(httpCli *http.Client, os string, arch string) (version string, commit string, url string, err error) {
|
|
var resp *http.Response
|
|
var errs []error
|
|
for _, addr := range address {
|
|
resp, err = httpCli.Get(addr)
|
|
if err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
if resp == nil {
|
|
aggregate := utilerrors.NewAggregate(errs)
|
|
err = fmt.Errorf("failed to call github api, err: %v", aggregate)
|
|
return
|
|
}
|
|
|
|
var all []byte
|
|
all, err = io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
err = fmt.Errorf("failed to read all response from github api, err: %v", err)
|
|
return
|
|
}
|
|
var m RootEntity
|
|
err = json.Unmarshal(all, &m)
|
|
if err != nil {
|
|
err = fmt.Errorf("failed to unmarshal response, err: %v", err)
|
|
return
|
|
}
|
|
version = m.TagName
|
|
commit = m.TargetCommitish
|
|
for _, asset := range m.Assets {
|
|
if strings.Contains(asset.Name, arch) && strings.Contains(asset.Name, os) {
|
|
url = asset.BrowserDownloadUrl
|
|
break
|
|
}
|
|
}
|
|
if len(url) == 0 {
|
|
var found bool
|
|
// if os is not windows and darwin, default is linux
|
|
if !sets.New[string]("windows", "darwin").Has(os) {
|
|
for _, asset := range m.Assets {
|
|
if strings.Contains(asset.Name, "linux") && strings.Contains(asset.Name, arch) {
|
|
url = asset.BrowserDownloadUrl
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
u := "https://github.com/wencaiwulue/kubevpn/releases/latest"
|
|
err = fmt.Errorf("Can not found latest version url of KubeVPN, you can download it manually: \n%s\n", u)
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// https://api.github.com/repos/kubenetworks/kubevpn/releases
|
|
// https://github.com/kubenetworks/kubevpn/releases/download/v1.1.13/kubevpn-windows-arm64.exe
|
|
func Download(client *http.Client, url string, filename string, stdout, stderr io.Writer) error {
|
|
get, err := client.Get(url)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer get.Body.Close()
|
|
total := float64(get.ContentLength) / 1024 / 1024
|
|
s := fmt.Sprintf("Length: %d (%0.2fM)\n", get.ContentLength, total)
|
|
log.Info(s)
|
|
io.WriteString(stdout, s)
|
|
|
|
var f *os.File
|
|
f, err = os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
bar := progressbar.NewOptions(int(get.ContentLength),
|
|
progressbar.OptionSetWriter(stdout),
|
|
progressbar.OptionEnableColorCodes(true),
|
|
progressbar.OptionShowBytes(true),
|
|
progressbar.OptionSetWidth(50),
|
|
progressbar.OptionOnCompletion(func() {
|
|
_, _ = fmt.Fprint(stderr, "\n")
|
|
}),
|
|
progressbar.OptionSetRenderBlankState(true),
|
|
progressbar.OptionSetDescription("Writing temp file..."),
|
|
progressbar.OptionSetTheme(progressbar.Theme{
|
|
Saucer: "=",
|
|
SaucerHead: ">",
|
|
SaucerPadding: " ",
|
|
BarStart: "[",
|
|
BarEnd: "]",
|
|
}))
|
|
buf := make([]byte, 10<<(10*2)) // 10M
|
|
_, err = io.CopyBuffer(io.MultiWriter(f, bar), get.Body, buf)
|
|
return err
|
|
}
|
|
|
|
func UnzipKubeVPNIntoFile(zipFile, filename string) error {
|
|
archive, err := zip.OpenReader(zipFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer archive.Close()
|
|
|
|
var fi *zip.File
|
|
for _, f := range archive.File {
|
|
if strings.Contains(f.Name, "kubevpn") {
|
|
fi = f
|
|
break
|
|
}
|
|
}
|
|
|
|
if fi == nil {
|
|
return fmt.Errorf("can not found kubevpn")
|
|
}
|
|
|
|
err = os.MkdirAll(filepath.Dir(filename), os.ModePerm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var dstFile *os.File
|
|
dstFile, err = os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fi.Mode())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer dstFile.Close()
|
|
|
|
var fileInArchive io.ReadCloser
|
|
fileInArchive, err = fi.Open()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fileInArchive.Close()
|
|
|
|
_, err = io.Copy(dstFile, fileInArchive)
|
|
return err
|
|
}
|
|
|
|
type RootEntity struct {
|
|
Url string `json:"url"`
|
|
AssetsUrl string `json:"assets_url"`
|
|
UploadUrl string `json:"upload_url"`
|
|
HtmlUrl string `json:"html_url"`
|
|
Id int64 `json:"id"`
|
|
NodeId string `json:"node_id"`
|
|
TagName string `json:"tag_name"`
|
|
TargetCommitish string `json:"target_commitish"`
|
|
Name string `json:"name"`
|
|
Draft bool `json:"draft"`
|
|
Prerelease bool `json:"prerelease"`
|
|
CreatedAt string `json:"created_at"`
|
|
PublishedAt string `json:"published_at"`
|
|
Assets []AssetsEntity `json:"assets"`
|
|
TarballUrl string `json:"tarball_url"`
|
|
ZipballUrl string `json:"zipball_url"`
|
|
Body string `json:"body"`
|
|
Reactions ReactionsEntity `json:"reactions"`
|
|
}
|
|
|
|
type AuthorEntity struct {
|
|
Login string `json:"login"`
|
|
Id int64 `json:"id"`
|
|
NodeId string `json:"node_id"`
|
|
AvatarUrl string `json:"avatar_url"`
|
|
GravatarId string `json:"gravatar_id"`
|
|
Url string `json:"url"`
|
|
HtmlUrl string `json:"html_url"`
|
|
FollowersUrl string `json:"followers_url"`
|
|
FollowingUrl string `json:"following_url"`
|
|
GistsUrl string `json:"gists_url"`
|
|
StarredUrl string `json:"starred_url"`
|
|
SubscriptionsUrl string `json:"subscriptions_url"`
|
|
OrganizationsUrl string `json:"organizations_url"`
|
|
ReposUrl string `json:"repos_url"`
|
|
EventsUrl string `json:"events_url"`
|
|
ReceivedEventsUrl string `json:"received_events_url"`
|
|
Type string `json:"type"`
|
|
SiteAdmin bool `json:"site_admin"`
|
|
}
|
|
|
|
type AssetsEntity struct {
|
|
Url string `json:"url"`
|
|
Id int64 `json:"id"`
|
|
NodeId string `json:"node_id"`
|
|
Name string `json:"name"`
|
|
Label string `json:"label"`
|
|
Uploader UploaderEntity `json:"uploader"`
|
|
ContentType string `json:"content_type"`
|
|
State string `json:"state"`
|
|
Size int64 `json:"size"`
|
|
DownloadCount int64 `json:"download_count"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
BrowserDownloadUrl string `json:"browser_download_url"`
|
|
}
|
|
|
|
type UploaderEntity struct {
|
|
Login string `json:"login"`
|
|
Id int64 `json:"id"`
|
|
NodeId string `json:"node_id"`
|
|
AvatarUrl string `json:"avatar_url"`
|
|
GravatarId string `json:"gravatar_id"`
|
|
Url string `json:"url"`
|
|
HtmlUrl string `json:"html_url"`
|
|
FollowersUrl string `json:"followers_url"`
|
|
FollowingUrl string `json:"following_url"`
|
|
GistsUrl string `json:"gists_url"`
|
|
StarredUrl string `json:"starred_url"`
|
|
SubscriptionsUrl string `json:"subscriptions_url"`
|
|
OrganizationsUrl string `json:"organizations_url"`
|
|
ReposUrl string `json:"repos_url"`
|
|
EventsUrl string `json:"events_url"`
|
|
ReceivedEventsUrl string `json:"received_events_url"`
|
|
Type string `json:"type"`
|
|
SiteAdmin bool `json:"site_admin"`
|
|
}
|
|
|
|
type ReactionsEntity struct {
|
|
Url string `json:"url"`
|
|
TotalCount int64 `json:"total_count"`
|
|
Normal1 int64 `json:"+1"`
|
|
Normal11 int64 `json:"-1"`
|
|
Laugh int64 `json:"laugh"`
|
|
Hooray int64 `json:"hooray"`
|
|
Confused int64 `json:"confused"`
|
|
Heart int64 `json:"heart"`
|
|
Rocket int64 `json:"rocket"`
|
|
Eyes int64 `json:"eyes"`
|
|
}
|