更新 main.go
This commit is contained in:
112
main.go
112
main.go
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/subtle"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
@@ -21,6 +22,7 @@ const (
|
||||
downloadDir = "./chrome_versions"
|
||||
checkInterval = 24 * time.Hour
|
||||
maxRetries = 3
|
||||
versionAPI = "https://versionhistory.googleapis.com/v1/chrome/platforms/win64/channels/stable/versions"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -28,7 +30,6 @@ var (
|
||||
authEnabled bool
|
||||
port string
|
||||
keepVersions int
|
||||
chromeURL string
|
||||
)
|
||||
|
||||
type Version struct {
|
||||
@@ -37,12 +38,20 @@ type Version struct {
|
||||
Time time.Time
|
||||
}
|
||||
|
||||
type ChromeVersion struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type ChromeVersionResponse struct {
|
||||
Versions []ChromeVersion `json:"versions"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
authToken = getEnv("AUTH_TOKEN", "")
|
||||
authEnabled = getEnv("AUTH_ENABLED", "false") == "true" || authToken != ""
|
||||
port = getEnv("PORT", "8080")
|
||||
keepVersions, _ = strconv.Atoi(getEnv("KEEP_VERSIONS", "3"))
|
||||
chromeURL = getEnv("CHROME_URL", "https://dl.google.com/tag/s/appguid%3D%7B8A69D345-D564-463C-AFF1-A69D9E530F96%7D%26iid%3D%7B00000000-0000-0000-0000-000000000000%7D%26lang%3Dzh-CN%26browser%3D4%26usagestats%3D0%26appname%3DGoogle%2520Chrome%26needsadmin%3Dprefers%26ap%3Dx64-stable-statsdef_1%26installdataindex%3Dempty/chrome/install/ChromeStandaloneSetup64.exe")
|
||||
}
|
||||
|
||||
func getEnv(key, defaultValue string) string {
|
||||
@@ -56,7 +65,6 @@ func main() {
|
||||
os.MkdirAll(downloadDir, 0755)
|
||||
log.Printf("Auth enabled: %v, Port: %s, Keep versions: %d", authEnabled, port, keepVersions)
|
||||
|
||||
// 启动时立即检查一次
|
||||
log.Println("Performing initial check...")
|
||||
checkAndDownload()
|
||||
|
||||
@@ -79,34 +87,86 @@ func monitor() {
|
||||
}
|
||||
}
|
||||
|
||||
func checkAndDownload() {
|
||||
var data []byte
|
||||
var err error
|
||||
func getLatestVersion() (string, error) {
|
||||
resp, err := http.Get(versionAPI)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var versionResp ChromeVersionResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&versionResp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(versionResp.Versions) == 0 {
|
||||
return "", fmt.Errorf("no versions found")
|
||||
}
|
||||
|
||||
return versionResp.Versions[0].Version, nil
|
||||
}
|
||||
|
||||
func checkAndDownload() {
|
||||
version, err := getLatestVersion()
|
||||
if err != nil {
|
||||
log.Printf("Failed to get latest version: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Latest Chrome version: %s", version)
|
||||
|
||||
// 尝试多个可能的下载 URL 模式
|
||||
urls := []string{
|
||||
fmt.Sprintf("https://dl.google.com/release2/chrome/%%s_%s/%s_chrome_installer.exe", version, version),
|
||||
fmt.Sprintf("https://dl.google.com/tag/s/appguid%%3D%%7B8A69D345-D564-463C-AFF1-A69D9E530F96%%7D%%26iid%%3D%%7B00000000-0000-0000-0000-000000000000%%7D%%26lang%%3Dzh-CN%%26browser%%3D4%%26usagestats%%3D0%%26appname%%3DGoogle%%2520Chrome%%26needsadmin%%3Dprefers%%26ap%%3Dx64-stable-statsdef_1%%26installdataindex%%3Dempty/chrome/install/ChromeStandaloneSetup64.exe"),
|
||||
}
|
||||
|
||||
var data []byte
|
||||
client := &http.Client{
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
log.Printf("Redirecting to: %s", req.URL.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
for _, urlPattern := range urls {
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
resp, err := http.Get(chromeURL)
|
||||
url := urlPattern
|
||||
if strings.Contains(url, "%s") {
|
||||
// 跳过需要 hash 的 URL
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("Trying URL: %s", url)
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
log.Printf("Attempt %d failed: %v", i+1, err)
|
||||
time.Sleep(time.Duration(i+1) * 10 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
contentLength := resp.Header.Get("Content-Length")
|
||||
log.Printf("Content-Type: %s, Content-Length: %s", contentType, contentLength)
|
||||
|
||||
data, err = io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
log.Printf("Attempt %d read failed: %v", i+1, err)
|
||||
if err == nil && len(data) > 10000000 && !strings.Contains(contentType, "text/html") {
|
||||
goto success
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Println("All retries failed")
|
||||
log.Printf("Invalid response (size: %d bytes)", len(data))
|
||||
time.Sleep(time.Duration(i+1) * 10 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("All download attempts failed")
|
||||
return
|
||||
}
|
||||
|
||||
success:
|
||||
hash := fmt.Sprintf("%x", md5.Sum(data))
|
||||
filename := fmt.Sprintf("chrome_%s_%s.exe", time.Now().Format("20060102"), hash[:8])
|
||||
filename := fmt.Sprintf("chrome_%s_%s.exe", version, hash[:8])
|
||||
filepath := filepath.Join(downloadDir, filename)
|
||||
|
||||
if _, err := os.Stat(filepath); err == nil {
|
||||
@@ -192,14 +252,30 @@ func serveIndex(w http.ResponseWriter, r *http.Request) {
|
||||
<h1>Chrome Offline Versions</h1>
|
||||
<ul>
|
||||
{{range .Versions}}
|
||||
<li><a href="/download/{{.Filename}}{{if $.Token}}?token={{$.Token}}{{end}}">{{.Filename}}</a> ({{.Size}} bytes, {{.Time.Format "2006-01-02 15:04"}})</li>
|
||||
<li><a href="/download/{{.Filename}}{{if $.Token}}?token={{$.Token}}{{end}}">{{.Filename}}</a> ({{printf "%.2f" .SizeMB}} MB, {{.Time.Format "2006-01-02 15:04"}})</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
`))
|
||||
|
||||
type VersionDisplay struct {
|
||||
Filename string
|
||||
SizeMB float64
|
||||
Time time.Time
|
||||
}
|
||||
|
||||
var displayVersions []VersionDisplay
|
||||
for _, v := range versions {
|
||||
displayVersions = append(displayVersions, VersionDisplay{
|
||||
Filename: v.Filename,
|
||||
SizeMB: float64(v.Size) / 1024 / 1024,
|
||||
Time: v.Time,
|
||||
})
|
||||
}
|
||||
|
||||
tmpl.Execute(w, struct {
|
||||
Versions []Version
|
||||
Versions []VersionDisplay
|
||||
Token string
|
||||
}{versions, token})
|
||||
}{displayVersions, token})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user