From 57fe6986b0112d638ba01a57da495f3f1364afef Mon Sep 17 00:00:00 2001 From: TenderIronh Date: Mon, 17 Nov 2025 10:00:50 +0800 Subject: [PATCH] refactor update and fix token loss bug --- core/common.go | 117 +++++++++++++++++++++++++++++++++++++++++++++-- core/config.go | 96 +++++++++++++++++++------------------- core/protocol.go | 93 +++++++++++++++++++++++++++++++------ core/update.go | 101 ++++++++++++++++++++++++---------------- 4 files changed, 301 insertions(+), 106 deletions(-) diff --git a/core/common.go b/core/common.go index f8d559d..6f7de12 100644 --- a/core/common.go +++ b/core/common.go @@ -2,18 +2,22 @@ package openp2p import ( "bytes" + "context" "crypto/aes" "crypto/cipher" "crypto/tls" "encoding/binary" "encoding/json" "fmt" + "io" + "math" "math/big" "math/rand" "net" "net/http" "os" "os/exec" + "runtime" "strconv" "strings" "time" @@ -128,19 +132,19 @@ func netInfo() *NetInfo { client := &http.Client{Transport: tr, Timeout: time.Second * 10} r, err := client.Get("https://ifconfig.co/json") if err != nil { - gLog.Println(LvDEBUG, "netInfo error:", err) + gLog.d("netInfo error:%s", err) continue } defer r.Body.Close() buf := make([]byte, 1024*64) n, err := r.Body.Read(buf) if err != nil { - gLog.Println(LvDEBUG, "netInfo error:", err) + gLog.d("netInfo error:%s", err) continue } rsp := NetInfo{} if err = json.Unmarshal(buf[:n], &rsp); err != nil { - gLog.Printf(LvERROR, "wrong NetInfo:%s", err) + gLog.e("wrong NetInfo:%s", err) continue } return &rsp @@ -280,3 +284,110 @@ func calculateChecksum(data []byte) uint16 { return uint16(^sum) } + +func min(nums ...int32) int32 { + if len(nums) == 0 { + return 0 // 如果没有输入,返回最大值 + } + + minVal := nums[0] + for _, num := range nums[1:] { + if num < minVal { + minVal = num + } + } + return minVal +} + +func calcRetryTimeRelay(x float64) float64 { + return 10 + math.Exp(0.8*(x-3.6)) +} +func calcRetryTimeDirect(x float64) float64 { + return 10 + math.Exp(2.8*(x-4)) +} + +func isAndroid() bool { + if runtime.GOOS == "android" { + return true + } + data, err := os.ReadFile("/proc/version") + if err != nil { + return false + } + return strings.Contains(string(data), "Android") +} + +func moveFile(src, dst string) error { + err := os.Rename(src, dst) + if err == nil { + return nil + } + // windows could not rename running executable, so copy then delete + if runtime.GOOS == "windows" { + err = copyFile(src, dst) + if err != nil { + return err + } + + os.Remove(src) + } + return nil +} + +func copyFile(src, dst string) error { + sourceFile, err := os.Open(src) + if err != nil { + return err + } + defer sourceFile.Close() + + destFile, err := os.Create(dst) + if err != nil { + return err + } + defer destFile.Close() + + _, err = io.Copy(destFile, sourceFile) + if err != nil { + return err + } + + return destFile.Sync() +} + +func resolveServerIP(host string) ([]string, error) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // 先系统 DNS + ips, err := net.DefaultResolver.LookupHost(ctx, host) + if err == nil && len(ips) > 0 { + gLog.i("system dns resolved %s -> %v", host, ips) + return ips, nil + } + + gLog.e("system dns resolve failed for %s: %v", host, err) + gLog.i("retry with fallback dns...") + + // 再 fallback dns + return lookupWithCustomDNS(ctx, host) +} +func lookupWithCustomDNS(ctx context.Context, domain string) ([]string, error) { + resolver := &net.Resolver{ + PreferGo: true, + Dial: func(ctx context.Context, network, address string) (net.Conn, error) { + dialer := &net.Dialer{Timeout: 5 * time.Second} + + // 先 119.29.29.29 + conn, err := dialer.DialContext(ctx, network, "119.29.29.29:53") + if err == nil { + return conn, nil + } + + // 再 8.8.8.8 + return dialer.DialContext(ctx, network, "8.8.8.8:53") + }, + } + + return resolver.LookupHost(ctx, domain) +} diff --git a/core/config.go b/core/config.go index 78097a1..7efb22d 100644 --- a/core/config.go +++ b/core/config.go @@ -77,14 +77,17 @@ type Config struct { Network NetworkConfig `json:"network"` Apps []*AppConfig `json:"apps"` - LogLevel int - MaxLogSize int - daemonMode bool - mtx sync.Mutex - sdwanMtx sync.Mutex - sdwan SDWANInfo - delNodes []*SDWANNode - addNodes []*SDWANNode + LogLevel int + MaxLogSize int + TLSInsecureSkipVerify bool + Forcev6 bool + daemonMode bool + mtx sync.RWMutex + fileMtx sync.Mutex + sdwanMtx sync.Mutex + sdwan SDWANInfo + delNodes []*SDWANNode + addNodes []*SDWANNode } func (c *Config) getSDWAN() SDWANInfo { @@ -251,31 +254,42 @@ func (c *Config) delete(app AppConfig) { } func (c *Config) save() { - // c.mtx.Lock() - // defer c.mtx.Unlock() // internal call + c.fileMtx.Lock() + defer c.fileMtx.Unlock() if c.Network.Token == 0 { + gLog.e("c.Network.Token == 0 skip save") return } - data, _ := json.MarshalIndent(c, "", " ") - err := os.WriteFile("config.json", data, 0644) - if err != nil { - gLog.Println(LvERROR, "save config.json error:", err) - } -} - -func (c *Config) saveCache() { - // c.mtx.Lock() - // defer c.mtx.Unlock() // internal call - if c.Network.Token == 0 { + data, err := json.MarshalIndent(c, "", " ") + if err != nil || len(data) < 16 { + gLog.e("MarshalIndent config.json error:%v, len=%d", err, len(data)) return } - data, _ := json.MarshalIndent(c, "", " ") - err := os.WriteFile("config.json0", data, 0644) + err = os.WriteFile("config.json0", data, 0644) if err != nil { - gLog.Println(LvERROR, "save config.json0 error:", err) + gLog.e("save config.json error:%v", err) } + + // verify if the file is written correctly + data, err = os.ReadFile("config.json0") + if err != nil { + return + } + var tmpConfig Config + err = json.Unmarshal(data, &tmpConfig) + if err != nil { + gLog.e("parse config.json error:", err) + return + } + err = os.Rename("config.json0", "config.json") + if err != nil { + gLog.e("rename config file error:%v", err) + } + } +// -d run, then worker serverport always WsPort. +// func init() { func init() { gConf.LogLevel = int(LvINFO) gConf.MaxLogSize = 1024 * 1024 @@ -286,19 +300,19 @@ func init() { } func (c *Config) load() error { - c.mtx.Lock() - defer c.mtx.Unlock() + c.fileMtx.Lock() + defer c.fileMtx.Unlock() data, err := os.ReadFile("config.json") if err != nil { - return c.loadCache() + return err } + c.mtx.Lock() + defer c.mtx.Unlock() err = json.Unmarshal(data, &c) if err != nil { - gLog.Println(LvERROR, "parse config.json error:", err) - // try cache - return c.loadCache() + gLog.e("parse config.json error:", err) + return err } - // load ok. cache it var filteredApps []*AppConfig // filter memapp for _, app := range c.Apps { if app.SrcPort != 0 { @@ -306,19 +320,7 @@ func (c *Config) load() error { } } c.Apps = filteredApps - c.saveCache() - return err -} - -func (c *Config) loadCache() error { - data, err := os.ReadFile("config.json0") - if err != nil { - return err - } - err = json.Unmarshal(data, &c) - if err != nil { - gLog.Println(LvERROR, "parse config.json0 error:", err) - } + c.Network.natType = NATUnknown return err } @@ -326,7 +328,6 @@ func (c *Config) loadCache() error { func (c *Config) setToken(token uint64) { c.mtx.Lock() defer c.mtx.Unlock() - defer c.save() if token != 0 { c.Network.Token = token } @@ -334,13 +335,11 @@ func (c *Config) setToken(token uint64) { func (c *Config) setUser(user string) { c.mtx.Lock() defer c.mtx.Unlock() - defer c.save() c.Network.User = user } func (c *Config) setNode(node string) { c.mtx.Lock() defer c.mtx.Unlock() - defer c.save() c.Network.Node = node c.Network.nodeID = NodeNameToID(c.Network.Node) } @@ -379,6 +378,7 @@ type NetworkConfig struct { mac string os string publicIP string + previousIP string // for publicIP change detect natType int hasIPv4 int publicIPv6 string // must lowwer-case not save json @@ -505,9 +505,9 @@ func parseParams(subCommand string, cmd string) { gConf.Network.UDPPort1 = UDPPort1 gConf.Network.UDPPort2 = UDPPort2 gLog.setLevel(LogLevel(gConf.LogLevel)) + gLog.setMaxSize(int64(gConf.MaxLogSize)) if *notVerbose { gLog.setMode(LogFile) } - // gConf.mtx.Unlock() gConf.save() } diff --git a/core/protocol.go b/core/protocol.go index 8656c26..c13677b 100644 --- a/core/protocol.go +++ b/core/protocol.go @@ -74,7 +74,7 @@ func encodeHeader(mainType uint16, subType uint16, len uint32) []byte { return headBuf.Bytes() } -// Message type +// Message main type const ( MsgLogin = 0 MsgHeartbeat = 1 @@ -109,6 +109,8 @@ const ( MsgPushReportMemApps = 17 MsgPushServerSideSaveMemApp = 18 MsgPushCheckRemoteService = 19 + MsgPushSpecTunnel = 20 + MsgPushReportHeap = 21 ) // MsgP2P sub type message @@ -128,6 +130,9 @@ const ( MsgRelayHeartbeatAck MsgNodeData MsgRelayNodeData + MsgNodeDataMP + MsgNodeDataMPAck + MsgRelayHeartbeatAck2 ) // MsgRelay sub type message @@ -243,6 +248,21 @@ func newMessage(mainType uint16, subType uint16, packet interface{}) ([]byte, er return writeBytes, nil } +func newMessageWithBuff(mainType uint16, subType uint16, data []byte) ([]byte, error) { + head := openP2PHeader{ + uint32(len(data)), + mainType, + subType, + } + headBuf := new(bytes.Buffer) + err := binary.Write(headBuf, binary.LittleEndian, head) + if err != nil { + return nil, err + } + writeBytes := append(headBuf.Bytes(), data...) + return writeBytes, nil +} + func NodeNameToID(name string) uint64 { return crc64.Checksum([]byte(name), crc64.MakeTable(crc64.ISO)) } @@ -339,13 +359,15 @@ type RelayNodeRsp struct { } type AddRelayTunnelReq struct { - From string `json:"from,omitempty"` - RelayName string `json:"relayName,omitempty"` - RelayTunnelID uint64 `json:"relayTunnelID,omitempty"` - RelayToken uint64 `json:"relayToken,omitempty"` - RelayMode string `json:"relayMode,omitempty"` - AppID uint64 `json:"appID,omitempty"` // deprecated - AppKey uint64 `json:"appKey,omitempty"` // deprecated + From string `json:"from,omitempty"` + RelayName string `json:"relayName,omitempty"` + RelayTunnelID uint64 `json:"relayTunnelID,omitempty"` + RelayToken uint64 `json:"relayToken,omitempty"` + RelayMode string `json:"relayMode,omitempty"` + AppID uint64 `json:"appID,omitempty"` // deprecated + AppKey uint64 `json:"appKey,omitempty"` // deprecated + UnderlayProtocol string `json:"underlayProtocol,omitempty"` // quic or kcp, default quic + PunchPriority int `json:"punchPriority,omitempty"` } type APPKeySync struct { @@ -354,9 +376,10 @@ type APPKeySync struct { } type RelayHeartbeat struct { - From string `json:"from,omitempty"` - RelayTunnelID uint64 `json:"relayTunnelID,omitempty"` - AppID uint64 `json:"appID,omitempty"` + From string `json:"from,omitempty"` + RelayTunnelID uint64 `json:"relayTunnelID,omitempty"` + RelayTunnelID2 uint64 `json:"relayTunnelID2,omitempty"` + AppID uint64 `json:"appID,omitempty"` } type ReportBasic struct { @@ -415,13 +438,16 @@ type AppInfo struct { } type ReportApps struct { - Apps []AppInfo + Apps []AppInfo + TunError string `json:"tunError,omitempty"` } type ReportLogReq struct { - FileName string `json:"fileName,omitempty"` - Offset int64 `json:"offset,omitempty"` - Len int64 `json:"len,omitempty"` + FileName string `json:"fileName,omitempty"` + Offset int64 `json:"offset,omitempty"` + Len int64 `json:"len,omitempty"` + IsSetLogLevel int64 `json:"isSetLogLevel,omitempty"` + LogLevel int64 `json:"loglevel,omitempty"` } type ReportLogRsp struct { FileName string `json:"fileName,omitempty"` @@ -434,6 +460,7 @@ type UpdateInfo struct { Error int `json:"error,omitempty"` ErrorDetail string `json:"errorDetail,omitempty"` Url string `json:"url,omitempty"` + Url2 string `json:"url2,omitempty"` } type NetInfo struct { @@ -467,6 +494,7 @@ type ProfileInfo struct { type EditNode struct { NewName string `json:"newName,omitempty"` Bandwidth int `json:"bandwidth,omitempty"` + Forcev6 int `json:"forcev6,omitempty"` } type QueryPeerInfoReq struct { @@ -501,6 +529,8 @@ type SDWANInfo struct { ForceRelay int32 `json:"forceRelay,omitempty"` PunchPriority int32 `json:"punchPriority,omitempty"` Enable int32 `json:"enable,omitempty"` + TunnelNum int32 `json:"tunnelNum,omitempty"` + Mtu int32 `json:"mtu,omitempty"` Nodes []*SDWANNode } @@ -516,6 +546,10 @@ type ServerSideSaveMemApp struct { RelayTunnelID uint64 `json:"relayTunnelID,omitempty"` // rtid, if not 0 relay RelayMode string `json:"relayMode,omitempty"` AppID uint64 `json:"appID,omitempty"` + AppKey uint64 `json:"appKey,omitempty"` + RelayIndex uint32 `json:"relayIndex,omitempty"` + TunnelNum uint32 `json:"tunnelNum,omitempty"` + SrcPort uint32 `json:"srcPort,omitempty"` } type CheckRemoteService struct { @@ -523,6 +557,10 @@ type CheckRemoteService struct { Port uint32 `json:"port,omitempty"` } +type SpecTunnel struct { + TunnelIndex uint32 `json:"tunnelIndex,omitempty"` +} + const rootCA = `-----BEGIN CERTIFICATE----- MIIDhTCCAm0CFHm0cd8dnGCbUW/OcS56jf0gvRk7MA0GCSqGSIb3DQEBCwUAMH4x CzAJBgNVBAYTAkNOMQswCQYDVQQIDAJHRDETMBEGA1UECgwKb3BlbnAycC5jbjET @@ -545,6 +583,31 @@ RVtXS+DplMClQ5QSlv3StwcWOsjyiAimNfLEU5xoEfq17yOJUTU1OTL4YOt16QUc C1tnzFr3k/ioqFR7cnyzNrbjlfPOmO9l2WReEbMP3bvaSHm6EcpJKS8= -----END CERTIFICATE-----` +const rootEdgeCA = `-----BEGIN CERTIFICATE----- +MIID/zCCAuegAwIBAgIUI53UqyuJSa74NFIKherg5WTjtl4wDQYJKoZIhvcNAQEL +BQAwgYYxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJHRDETMBEGA1UECgwKb3BlbnAy +cC5jbjETMBEGA1UECwwKb3BlbnAycC5jbjEbMBkGA1UEAwwSb3BlbnAycC5jbiBS +b290IENBMSMwIQYJKoZIhvcNAQkBFhRvcGVucDJwLmNuQGdtYWlsLmNvbTAeFw0y +NTA5MDMwNTExMTBaFw0zNTA5MDEwNTExMTBaMIGGMQswCQYDVQQGEwJDTjELMAkG +A1UECAwCR0QxEzARBgNVBAoMCm9wZW5wMnAuY24xEzARBgNVBAsMCm9wZW5wMnAu +Y24xGzAZBgNVBAMMEm9wZW5wMnAuY24gUm9vdCBDQTEjMCEGCSqGSIb3DQEJARYU +b3BlbnAycC5jbkBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC/aHC0opWx1MFkXYI+Mm0CkMi7nB5XaD3K/DGGtA/kadhayFSWb6Y2+UWW +s6OYBy7NmQRJgTedS4siQA6JEG4H3FBbz8URLt4TH/EP9+6QB0Z+P0arvUXNkl4k +7cALmblaiqjq2M199+FWKhDWH2vMr1htY9Y3ldivLRMeH76diKgf8NvsX+wGR8bZ +4MlJMFln0UeUYKIbekK7DmA5/9f2A/2Nrmi84PKGHU+0ZjB7gik/slW5zH0k7e+S +wNtTuf8+6+t/LcJK9dWsS6f5+DOWmLcIWs6s/VMP9ODEzlY/hKMFk53+H+AjAZY/ +J/qhOxLXMNlNjdjwSEFPBY/vwVEnAgMBAAGjYzBhMB0GA1UdDgQWBBTXSSeIvz/R +6A1pz0H4xBlV1Vu9kTAfBgNVHSMEGDAWgBTXSSeIvz/R6A1pz0H4xBlV1Vu9kTAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC +AQEABqvvKwM+k2NfIFf9tzo1EsD4rQunyn6K5Zhf/kspb9++2Onw/lDlOErxSLLz +C5aXn+B48honQeYEL/cYhH4duVQb0Zk71iF/PKDxYvF79Xbx9k7Kzg6RryaH8ZfQ +pyEao+Uc6O895F+SLBog5aHIbz8gFNCRVaSAv3xpUIyQ/haxyHHapaLqt/ueNFVP +qEG+9R41q55rEYb2ltINhumS3gb4qOcKI5pHuAw42pF8SShqaBIfFXSZ4u9ib7/k +CvHN0kDYavV6NRiCSRF6wMxmaF70WpfqQhGdw0WyIzJfMOtSdvctjfNCoaWy2V2s +nLaJXgiPehxIVGNC9dk/ZZzI2g== +-----END CERTIFICATE-----` + const ISRGRootX1 = `-----BEGIN CERTIFICATE----- MIIEJjCCAw6gAwIBAgISAztStWq026ej0RCsk3ErbUdPMA0GCSqGSIb3DQEBCwUA MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD diff --git a/core/update.go b/core/update.go index 6e9ecaf..24d6797 100644 --- a/core/update.go +++ b/core/update.go @@ -19,21 +19,21 @@ import ( ) func update(host string, port int) error { - gLog.Println(LvINFO, "update start") - defer gLog.Println(LvINFO, "update end") + gLog.i("update start") + defer gLog.i("update end") caCertPool, err := x509.SystemCertPool() if err != nil { - gLog.Println(LvERROR, "Failed to load system root CAs:", err) - } else { + gLog.e("Failed to load system root CAs:%s", err) caCertPool = x509.NewCertPool() } caCertPool.AppendCertsFromPEM([]byte(rootCA)) + caCertPool.AppendCertsFromPEM([]byte(rootEdgeCA)) caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1)) c := http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{RootCAs: caCertPool, - InsecureSkipVerify: false}, + InsecureSkipVerify: gConf.TLSInsecureSkipVerify}, }, Timeout: time.Second * 30, } @@ -41,32 +41,36 @@ func update(host string, port int) error { goarch := runtime.GOARCH rsp, err := c.Get(fmt.Sprintf("https://%s:%d/api/v1/update?fromver=%s&os=%s&arch=%s&user=%s&node=%s", host, port, OpenP2PVersion, goos, goarch, url.QueryEscape(gConf.Network.User), url.QueryEscape(gConf.Network.Node))) if err != nil { - gLog.Println(LvERROR, "update:query update list failed:", err) + gLog.e("update:query update list failed:%s", err) return err } defer rsp.Body.Close() if rsp.StatusCode != http.StatusOK { - gLog.Println(LvERROR, "get update info error:", rsp.Status) + gLog.e("get update info error:%s", rsp.Status) return err } rspBuf, err := ioutil.ReadAll(rsp.Body) if err != nil { - gLog.Println(LvERROR, "update:read update list failed:", err) + gLog.e("update:read update list failed:%s", err) return err } updateInfo := UpdateInfo{} if err = json.Unmarshal(rspBuf, &updateInfo); err != nil { - gLog.Println(LvERROR, rspBuf, " update info decode error:", err) + gLog.e("%s update info decode error:%s", string(rspBuf), err) return err } if updateInfo.Error != 0 { - gLog.Println(LvERROR, "update error:", updateInfo.Error, updateInfo.ErrorDetail) + gLog.e("update error:%d,%s", updateInfo.Error, updateInfo.ErrorDetail) return err } err = updateFile(updateInfo.Url, "", "openp2p") if err != nil { - gLog.Println(LvERROR, "update: download failed:", err) - return err + gLog.e("update: download failed:%s, retry...", err) + err = updateFile(updateInfo.Url2, "", "openp2p") + if err != nil { + gLog.e("update: download failed:%s", err) + return err + } } return nil } @@ -74,66 +78,79 @@ func update(host string, port int) error { func downloadFile(url string, checksum string, dstFile string) error { output, err := os.OpenFile(dstFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0776) if err != nil { - gLog.Printf(LvERROR, "OpenFile %s error:%s", dstFile, err) + gLog.e("OpenFile %s error:%s", dstFile, err) return err } caCertPool, err := x509.SystemCertPool() if err != nil { - gLog.Println(LvERROR, "Failed to load system root CAs:", err) - } else { + gLog.e("Failed to load system root CAs:%s", err) caCertPool = x509.NewCertPool() } caCertPool.AppendCertsFromPEM([]byte(rootCA)) + caCertPool.AppendCertsFromPEM([]byte(rootEdgeCA)) caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1)) tr := &http.Transport{ TLSClientConfig: &tls.Config{ RootCAs: caCertPool, - InsecureSkipVerify: false}, + InsecureSkipVerify: gConf.TLSInsecureSkipVerify}, } client := &http.Client{Transport: tr} response, err := client.Get(url) if err != nil { - gLog.Printf(LvERROR, "download url %s error:%s", url, err) + gLog.e("download url %s error:%s", url, err) output.Close() return err } defer response.Body.Close() n, err := io.Copy(output, response.Body) if err != nil { - gLog.Printf(LvERROR, "io.Copy error:%s", err) + gLog.e("io.Copy error:%s", err) output.Close() return err } output.Sync() output.Close() - gLog.Println(LvINFO, "download ", url, " ok") - gLog.Printf(LvINFO, "size: %d bytes", n) + gLog.i("download %s ok", url) + gLog.i("size: %d bytes", n) return nil } func updateFile(url string, checksum string, dst string) error { - gLog.Println(LvINFO, "download ", url) - tmpFile := filepath.Dir(os.Args[0]) + "/openp2p.tmp" + gLog.i("download %s", url) + tempDir := os.TempDir() + tmpFile := filepath.Join(tempDir, "openp2p.tmp") err := downloadFile(url, checksum, tmpFile) if err != nil { return err } - backupFile := os.Args[0] + "0" - err = os.Rename(os.Args[0], backupFile) // the old daemon process was using the 0 file, so it will prevent override it + backupBase := filepath.Base(os.Args[0]) + var backupFile string + if runtime.GOOS == "windows" { + backupFile = filepath.Join(tempDir, backupBase+"0") + } else { + backupFile = os.Args[0] + "0" // linux can not mv running executable to /tmp, because they are different volumns + } + gLog.i("backup file %s --> %s", os.Args[0], backupFile) + err = moveFile(os.Args[0], backupFile) if err != nil { - gLog.Printf(LvINFO, " rename %s error:%s, retry 1", os.Args[0], err) - backupFile = os.Args[0] + "1" - err = os.Rename(os.Args[0], backupFile) + if runtime.GOOS == "windows" { + backupFile = filepath.Join(tempDir, backupBase+"1") + } else { + backupFile = os.Args[0] + "1" // 1st update will mv deamon process to 0, 2nd update mv to 0 will failed, mv to 1 + } + gLog.i("backup file %s --> %s", os.Args[0], backupFile) + err = moveFile(os.Args[0], backupFile) if err != nil { - gLog.Printf(LvINFO, " rename %s error:%s", os.Args[0], err) + gLog.e(" rename %s error:%s", os.Args[0], err) + return err } } // extract - gLog.Println(LvINFO, "extract files") + gLog.i("extract files") err = extract(filepath.Dir(os.Args[0]), tmpFile) if err != nil { - gLog.Printf(LvERROR, "extract error:%s. revert rename", err) - os.Rename(backupFile, os.Args[0]) + gLog.e("extract error:%s. revert rename", err) + moveFile(backupFile, os.Args[0]) return err } os.Remove(tmpFile) @@ -224,16 +241,20 @@ func extractTgz(dst, src string) error { } func cleanTempFiles() { - tmpFile := os.Args[0] + "0" - if _, err := os.Stat(tmpFile); err == nil { - if err := os.Remove(tmpFile); err != nil { - gLog.Printf(LvDEBUG, " remove %s error:%s", tmpFile, err) + tempDir := os.TempDir() + backupBase := filepath.Base(os.Args[0]) + for i := 0; i < 2; i++ { + tmpFile := fmt.Sprintf("%s%d", os.Args[0], i) + if _, err := os.Stat(tmpFile); err == nil { + if err := os.Remove(tmpFile); err != nil { + gLog.d(" remove %s error:%s", tmpFile, err) + } } - } - tmpFile = os.Args[0] + "1" - if _, err := os.Stat(tmpFile); err == nil { - if err := os.Remove(tmpFile); err != nil { - gLog.Printf(LvDEBUG, " remove %s error:%s", tmpFile, err) + tmpFile = fmt.Sprintf("%s%s%d", tempDir, backupBase, i) + if _, err := os.Stat(tmpFile); err == nil { + if err := os.Remove(tmpFile); err != nil { + gLog.d(" remove %s error:%s", tmpFile, err) + } } } }