11package daemon
22
33import (
4+ "archive/tar"
5+ "compress/gzip"
46 "fmt"
57 "io"
68 "net/http"
79 "os"
810 "os/exec"
911 "path/filepath"
1012 "runtime"
13+ "strings"
1114
1215 "github.com/qingchencloud/cftunnel/internal/config"
1316)
1417
1518// CloudflaredPath 返回 cloudflared 二进制路径
1619func CloudflaredPath () string {
17- return filepath .Join (config .Dir (), "bin" , "cloudflared" )
20+ name := "cloudflared"
21+ if runtime .GOOS == "windows" {
22+ name = "cloudflared.exe"
23+ }
24+ return filepath .Join (config .Dir (), "bin" , name )
1825}
1926
2027// EnsureCloudflared 确保 cloudflared 已安装,未安装则自动下载
@@ -49,6 +56,12 @@ func download(dest string) error {
4956 return fmt .Errorf ("下载失败: HTTP %d" , resp .StatusCode )
5057 }
5158
59+ // macOS 的 cloudflared 是 tgz 格式,需要解压
60+ if strings .HasSuffix (url , ".tgz" ) {
61+ return extractTgz (resp .Body , dest )
62+ }
63+
64+ // Linux/Windows 是裸二进制,直接写入
5265 f , err := os .Create (dest )
5366 if err != nil {
5467 return err
@@ -57,13 +70,44 @@ func download(dest string) error {
5770 if _ , err := io .Copy (f , resp .Body ); err != nil {
5871 return err
5972 }
60- if err := os . Chmod ( dest , 0755 ); err != nil {
61- return err
73+ if runtime . GOOS != "windows" {
74+ os . Chmod ( dest , 0755 )
6275 }
6376 fmt .Printf ("cloudflared 已下载到 %s\n " , dest )
6477 return nil
6578}
6679
80+ func extractTgz (r io.Reader , dest string ) error {
81+ gr , err := gzip .NewReader (r )
82+ if err != nil {
83+ return fmt .Errorf ("解压失败: %w" , err )
84+ }
85+ defer gr .Close ()
86+ tr := tar .NewReader (gr )
87+ for {
88+ hdr , err := tr .Next ()
89+ if err == io .EOF {
90+ return fmt .Errorf ("tgz 中未找到 cloudflared" )
91+ }
92+ if err != nil {
93+ return fmt .Errorf ("解压失败: %w" , err )
94+ }
95+ if filepath .Base (hdr .Name ) == "cloudflared" {
96+ f , err := os .Create (dest )
97+ if err != nil {
98+ return err
99+ }
100+ defer f .Close ()
101+ if _ , err := io .Copy (f , tr ); err != nil {
102+ return err
103+ }
104+ os .Chmod (dest , 0755 )
105+ fmt .Printf ("cloudflared 已下载到 %s\n " , dest )
106+ return nil
107+ }
108+ }
109+ }
110+
67111func downloadURL () (string , error ) {
68112 const base = "https://github.com/cloudflare/cloudflared/releases/latest/download/"
69113 switch runtime .GOOS + "/" + runtime .GOARCH {
@@ -75,6 +119,10 @@ func downloadURL() (string, error) {
75119 return base + "cloudflared-linux-amd64" , nil
76120 case "linux/arm64" :
77121 return base + "cloudflared-linux-arm64" , nil
122+ case "windows/amd64" :
123+ return base + "cloudflared-windows-amd64.exe" , nil
124+ case "windows/arm64" :
125+ return base + "cloudflared-windows-amd64.exe" , nil
78126 default :
79127 return "" , fmt .Errorf ("不支持的平台: %s/%s" , runtime .GOOS , runtime .GOARCH )
80128 }
0 commit comments