From 22b4402737ad7a47edeac8d14782562b0b511ce6 Mon Sep 17 00:00:00 2001 From: ayflying Date: Fri, 31 Oct 2025 15:50:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E6=9C=AC=E5=9C=B0=E7=9A=84?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=80=BB=E8=BE=91=EF=BC=8C=E6=98=AF=E6=9C=89?= =?UTF-8?q?=E5=88=86=E7=A6=BB=E5=90=8E=E7=9A=84=E6=9B=B4=E6=96=B0=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/system/v1/update.go | 10 - internal/cmd/cmd.go | 4 +- internal/cmd/update.go | 109 ------- internal/controller/system/system_new.go | 8 - .../controller/system/system_v1_update.go | 70 ---- internal/logic/system/model.go | 64 ---- internal/logic/system/system.go | 2 - internal/logic/system/update.go | 301 ------------------ 8 files changed, 1 insertion(+), 567 deletions(-) delete mode 100644 internal/cmd/update.go delete mode 100644 internal/controller/system/system_v1_update.go delete mode 100644 internal/logic/system/model.go delete mode 100644 internal/logic/system/update.go diff --git a/api/system/v1/update.go b/api/system/v1/update.go index 9389238..b7b1f99 100644 --- a/api/system/v1/update.go +++ b/api/system/v1/update.go @@ -1,11 +1 @@ package v1 - -import "github.com/gogf/gf/v2/frame/g" - -type UpdateReq struct { - g.Meta `path:"/system/update" tags:"system" method:"get" sm:"更新服务端"` - Url string `json:"url" dc:"更新地址"` - Version string `json:"version" dc:"当前版本"` -} -type UpdateRes struct { -} diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index fc8db8d..486ce24 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -7,7 +7,6 @@ import ( "github.com/ayflying/p2p/internal/consts" "github.com/ayflying/p2p/internal/controller/p2p" - "github.com/ayflying/p2p/internal/controller/system" "github.com/ayflying/p2p/internal/service" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" @@ -18,7 +17,7 @@ import ( ) func init() { - err := Main.AddCommand(&Main, &Debug, &Update) + err := Main.AddCommand(&Main, &Debug) if err != nil { g.Log().Error(gctx.GetInitCtx(), err) return @@ -69,7 +68,6 @@ var ( group.Middleware(ghttp.MiddlewareHandlerResponse) group.Bind( p2p.NewV1(), - system.NewV1(), ) }) diff --git a/internal/cmd/update.go b/internal/cmd/update.go deleted file mode 100644 index d7630e0..0000000 --- a/internal/cmd/update.go +++ /dev/null @@ -1,109 +0,0 @@ -package cmd - -import ( - "bytes" - "context" - "fmt" - "path" - "runtime" - - systemV1 "github.com/ayflying/p2p/api/system/v1" - "github.com/ayflying/p2p/internal/service" - "github.com/gogf/gf/v2/crypto/gsha1" - "github.com/gogf/gf/v2/encoding/gcompress" - "github.com/gogf/gf/v2/encoding/gjson" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/os/gcfg" - "github.com/gogf/gf/v2/os/gcmd" - "github.com/gogf/gf/v2/os/gfile" -) - -var ( - Update = gcmd.Command{ - Name: "update", - Usage: "update", - Brief: "更新版本", - Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { - g.Log().Info(ctx, "准备上传更新文件") - //加载编辑配置文件 - g.Cfg("hack").GetAdapter().(*gcfg.AdapterFile).SetFileName("hack/config.yaml") - //获取文件名 - getName, err := g.Cfg("hack").Get(ctx, "gfcli.build.name") - name := getName.String() - - getPath, err := g.Cfg("hack").Get(ctx, "gfcli.build.path") - pathMain := getPath.String() - - //获取版本号 - getVersion, err := g.Cfg("hack").Get(ctx, "gfcli.build.version") - version := getVersion.String() - - // 拼接操作系统和架构(格式:OS_ARCH) - platform := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH) - - rootDir := "server_update" - - var versionFile = make(map[string]string) - var filePath = path.Join(pathMain, version, platform, name) - dirList, _ := gfile.ScanDir(path.Join(pathMain, version), "*", false) - for _, v := range dirList { - updatePlatform := gfile.Name(v) - updateFilePath := path.Join(rootDir, name, version, updatePlatform) - - var obj bytes.Buffer - g.Log().Debugf(ctx, "读取目录成功:%v", v) - fileMian := path.Join(v, name) - g.Log().Debugf(ctx, "判断当前文件是否存在:%v", fileMian) - if gfile.IsFile(fileMian) { - // 写入文件哈希 - versionFile[updatePlatform] = gsha1.MustEncryptFile(fileMian) - err = gcompress.GzipPathWriter(fileMian, &obj) - service.S3().PutObject(ctx, &obj, updateFilePath+".gz") - g.Log().Debugf(ctx, "成功上传文件到:%v", updateFilePath+".gz") - } - if gfile.IsFile(fileMian + ".exe") { - // 写入文件哈希 - versionFile[updatePlatform] = gsha1.MustEncryptFile(fileMian + ".exe") - err = gcompress.GzipPathWriter(fileMian+".exe", &obj) - service.S3().PutObject(ctx, &obj, updateFilePath+".gz") - g.Log().Debugf(ctx, "成功上传文件到:%v", updateFilePath+".gz") - } - - // 写入文件版本文件 - fileByte := gjson.MustEncode(versionFile) - service.S3().PutObject(ctx, bytes.NewReader(fileByte), path.Join(rootDir, name, "version.json")) - if err != nil { - g.Log().Error(ctx, err) - } - } - g.Log().Debugf(ctx, "当前获取到的地址为:%v", filePath) - - versionUrl := service.S3().GetCdnUrl(path.Join(rootDir, name)) - listVar := g.Cfg().MustGet(ctx, "message.list") - var p2pItem []struct { - Host string `json:"host"` - Port int `json:"port"` - SSL bool `json:"ssl"` - Ws string `json:"ws"` - } - listVar.Scan(&p2pItem) - for _, v := range p2pItem { - - url := "http" - if v.SSL == true { - url = "https" - } - url = fmt.Sprintf("%s://%s:%d/system/update", url, v.Host, v.Port) - - g.Log().Debugf(ctx, "开始上传到服务器:%v,file=%v", url, versionUrl) - _, err := g.Client().Get(ctx, url, systemV1.UpdateReq{ - Url: versionUrl, - Version: version, - }) - if err != nil { - g.Log().Error(ctx, err) - } - } - return - }} -) diff --git a/internal/controller/system/system_new.go b/internal/controller/system/system_new.go index 4237a85..b69e9ca 100644 --- a/internal/controller/system/system_new.go +++ b/internal/controller/system/system_new.go @@ -4,12 +4,4 @@ package system -import ( - "github.com/ayflying/p2p/api/system" -) - type ControllerV1 struct{} - -func NewV1() system.ISystemV1 { - return &ControllerV1{} -} diff --git a/internal/controller/system/system_v1_update.go b/internal/controller/system/system_v1_update.go deleted file mode 100644 index d9fd213..0000000 --- a/internal/controller/system/system_v1_update.go +++ /dev/null @@ -1,70 +0,0 @@ -package system - -import ( - "context" - "net/url" - "path" - - "github.com/ayflying/p2p/api/system/v1" - "github.com/ayflying/p2p/internal/service" - "github.com/gogf/gf/v2/crypto/gsha1" - "github.com/gogf/gf/v2/encoding/gjson" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/os/gcmd" - "github.com/gogf/gf/v2/os/gfile" -) - -func (c *ControllerV1) Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error) { - getRunFile := gcmd.GetArg(0).String() - fileSha, err := gsha1.EncryptFile(getRunFile) - g.Log().Debugf(ctx, "当前文件哈希值:%v", fileSha) - - versionUrl, _ := url.JoinPath(req.Url, "version.json") - resp, err := g.Client().Get(ctx, versionUrl) - var version map[string]string - gjson.DecodeTo(resp.ReadAll(), &version) - - for k, _ := range version { - //downloadUrl, _ := url.QueryUnescape(v) - downloadUrl, _ := url.JoinPath(req.Url, req.Version, k+".gz") - fileByte, err2 := g.Client().Get(ctx, downloadUrl) - if err2 != nil { - g.Log().Error(ctx, err2) - continue - } - putFile := path.Join("download", gfile.Basename(downloadUrl)) - err2 = gfile.PutBytes(putFile, fileByte.ReadAll()) - if err2 != nil { - g.Log().Error(ctx, err2) - continue - } - } - - type DataType struct { - File []byte `json:"file"` - Name string `json:"name"` - } - - //var GatewayMessage *message.GatewayMessage - - var msgData = struct { - Files []*DataType `json:"files"` - }{} - - msgData.Files = []*DataType{} - - files, _ := gfile.ScanDir("download", "*.gz") - - for _, v := range files { - msgData.Files = append(msgData.Files, &DataType{ - File: gfile.GetBytes(v), - Name: gfile.Basename(v), - }) - } - - service.P2P().SendAll("update", msgData) - - //更新自己的文件 - //err = service.System().Update(ctx) - return -} diff --git a/internal/logic/system/model.go b/internal/logic/system/model.go deleted file mode 100644 index d1e2f8d..0000000 --- a/internal/logic/system/model.go +++ /dev/null @@ -1,64 +0,0 @@ -package system - -import "time" - -type Author struct { - Login string `json:"login"` - Id int `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"` - UserViewType string `json:"user_view_type"` - SiteAdmin bool `json:"site_admin"` -} - -type Assets struct { - Url string `json:"url"` - Id int `json:"id"` - NodeId string `json:"node_id"` - Name string `json:"name"` - Label string `json:"label"` - Uploader *Uploader `json:"uploader"` - ContentType string `json:"content_type"` - State string `json:"state"` - Size int `json:"size"` - Digest string `json:"digest"` - DownloadCount int `json:"download_count"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - BrowserDownloadUrl string `json:"browser_download_url"` -} - -type Uploader struct { - Login string `json:"login"` - Id int `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"` - UserViewType string `json:"user_view_type"` - SiteAdmin bool `json:"site_admin"` -} diff --git a/internal/logic/system/system.go b/internal/logic/system/system.go index bf1bb5c..d876094 100644 --- a/internal/logic/system/system.go +++ b/internal/logic/system/system.go @@ -3,7 +3,6 @@ package system import ( "context" - "github.com/ayflying/p2p/internal/service" updateGithub "github.com/ayflying/update-github-release" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gcron" @@ -17,7 +16,6 @@ func New() *sSystem { } func init() { - service.RegisterSystem(New()) getDev, _ := g.Cfg().GetWithEnv(gctx.New(), "dev") if !getDev.Bool() { diff --git a/internal/logic/system/update.go b/internal/logic/system/update.go deleted file mode 100644 index 01fd076..0000000 --- a/internal/logic/system/update.go +++ /dev/null @@ -1,301 +0,0 @@ -package system - -import ( - "archive/tar" - "compress/gzip" - "context" - "encoding/json" - "fmt" - "io" - "log" - "net/http" - "os" - "os/exec" - "path" - "path/filepath" - "runtime" - "strings" - "time" - - "github.com/ayflying/p2p/internal/service" - "github.com/gogf/gf/v2/encoding/gcompress" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/net/ghttp" - "github.com/gogf/gf/v2/os/gcmd" - "github.com/gogf/gf/v2/os/gctx" - "github.com/gogf/gf/v2/os/gfile" -) - -// 本地版本号(建议从编译参数注入,如 -ldflags "-X main.version=v0.1.3") -const versionFile = "version.txt" - -var localVersion = "v0.0.0" - -// 对应 GitHub API 响应的核心字段(按需精简) -type GitHubRelease struct { - Url string `json:"url"` - AssetsUrl string `json:"assets_url"` - UploadUrl string `json:"upload_url"` - HtmlUrl string `json:"html_url"` - Id int `json:"id"` - TagName string `json:"tag_name"` - Assets []*Assets `json:"assets"` - NodeId string `json:"node_id"` - TargetCommitish string `json:"target_commitish"` - Name string `json:"name"` - Draft bool `json:"draft"` - Immutable bool `json:"immutable"` - Prerelease bool `json:"prerelease"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - PublishedAt time.Time `json:"published_at"` - TarballUrl string `json:"tarball_url"` - ZipballUrl string `json:"zipball_url"` - Body string `json:"body"` -} - -func (s *sSystem) Update(ctx context.Context, gzFile string) (err error) { - //拼接操作系统和架构(格式:OS_ARCH) - platform := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH) - - runFile := gcmd.GetArg(0).String() - oldFile, err := service.System().RenameRunningFile(runFile) - g.Log().Debugf(ctx, "执行文件改名为%v", oldFile) - if gzFile == "" { - gzFile = path.Join("download", platform+".gz") - } - //结束后删除压缩包 - defer gfile.RemoveFile(gzFile) - - ext := gfile.Ext(gzFile) - if ext == ".zip" { - g.Log().Debugf(ctx, "zip解压%v到%v", gzFile, gfile.Dir(runFile)) - err = gcompress.UnZipFile(gzFile, gfile.Dir(runFile)) - } else { - g.Log().Debugf(ctx, "gzip解压%v到%v", gzFile, gfile.Dir(runFile)) - err = s.UnTarGz(gzFile, gfile.Dir(runFile)) - } - if err != nil { - return - } - //修改文件权限为755 - err = gfile.Chmod(runFile, 0755) - - go func() { - log.Println("5秒后开始重启...") - time.Sleep(5 * time.Second) - - if err = service.System().RestartSelf(); err != nil { - log.Fatalf("重启失败:%v", err) - } - }() - return -} - -// UnTarGz 解压tar.gz文件到指定目录 -func (s *sSystem) UnTarGz(tarGzFileName, targetDir string) (err error) { - // 打开tar.gz文件 - file, err := os.Open(tarGzFileName) - if err != nil { - return err - } - defer file.Close() - - // 创建gzip reader - gzr, err := gzip.NewReader(file) - if err != nil { - return err - } - defer gzr.Close() - - // 创建tar reader - tr := tar.NewReader(gzr) - - // 遍历tar中的每个文件 - for { - hdr, err := tr.Next() - if err == io.EOF { - // 到达文件末尾,退出循环 - break - } - if err != nil { - return err - } - - // 构建解压后的文件路径 - targetPath := targetDir + string(os.PathSeparator) + hdr.Name - - // 如果是目录,创建目录 - if hdr.Typeflag == tar.TypeDir { - err := os.MkdirAll(targetPath, 0755) - if err != nil { - return err - } - continue - } - - // 如果是文件,创建文件并写入内容 - outFile, err := os.Create(targetPath) - if err != nil { - return err - } - defer outFile.Close() - - _, err = io.Copy(outFile, tr) - if err != nil { - return err - } - } - - return -} - -// RestartSelf 实现 Windows 平台下的程序自重启 -func (s *sSystem) RestartSelf() error { - ctx := gctx.New() - // 判断是否为linux平台 - if runtime.GOOS == "linux" { - err := ghttp.RestartAllServer(ctx, os.Args[0]) - if err != nil { - g.Log().Errorf(ctx, "重启失败:%v", err) - } - return err - } - - // 1. 获取当前程序的绝对路径 - exePath, err := os.Executable() - if err != nil { - return err - } - // 处理路径中的符号链接(确保路径正确) - exePath, err = filepath.EvalSymlinks(exePath) - if err != nil { - return err - } - - // 2. 获取命令行参数(os.Args[0] 是程序名,实际参数从 os.Args[1:] 开始) - args := os.Args[1:] - - // 3. 构建新进程命令(路径为当前程序,参数为原参数) - cmd := exec.Command(exePath, args...) - // 设置新进程的工作目录与当前进程一致 - cmd.Dir, err = os.Getwd() - if err != nil { - return err - } - - // 新进程的输出继承当前进程的标准输出(可选,根据需求调整) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Stdin = os.Stdin - - // 4. 启动新进程(非阻塞,Start() 后立即返回) - if err := cmd.Start(); err != nil { - return err - } - - // 5. 新进程启动成功后,退出当前进程 - os.Exit(0) - return nil // 理论上不会执行到这里 -} - -// RenameRunningFile 重命名正在运行的程序文件(如 message.exe → message.exe~) -func (s *sSystem) RenameRunningFile(exePath string) (string, error) { - // 目标备份文件名(message.exe → message.exe~) - backupPath := exePath + "~" - - // 先删除已存在的备份文件(若有) - if _, err := os.Stat(backupPath); err == nil { - if err := os.Remove(backupPath); err != nil { - return "", fmt.Errorf("删除旧备份文件失败: %v", err) - } - } - - // 重命名正在运行的 exe 文件 - // 关键:Windows 允许对锁定的文件执行重命名操作 - if err := os.Rename(exePath, backupPath); err != nil { - return "", fmt.Errorf("重命名运行中文件失败: %v", err) - } - return backupPath, nil -} - -// 简化版版本对比(仅适用于 vX.Y.Z 格式) -func (s *sSystem) isNewVersion(local, latest string) bool { - // 移除前缀 "v",按 "." 分割成数字切片 - localParts := strings.Split(strings.TrimPrefix(local, "v"), ".") - latestParts := strings.Split(strings.TrimPrefix(latest, "v"), ".") - - // 逐段对比版本号(如 0.1.3 vs 0.1.4 → 后者更新) - for i := 0; i < len(localParts) && i < len(latestParts); i++ { - if localParts[i] < latestParts[i] { - return true - } else if localParts[i] > latestParts[i] { - return false - } - } - // 若前缀相同,长度更长的版本更新(如 0.1 vs 0.1.1) - return len(localParts) < len(latestParts) -} - -func (s *sSystem) getLatestVersion() (string, []*Assets, error) { - apiURL := "https://api.github.com/repos/ayflying/p2p/releases/latest" - resp, err := http.Get(apiURL) - if err != nil { - return "", nil, fmt.Errorf("请求失败:%v", err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return "", nil, fmt.Errorf("API 响应错误:%d", resp.StatusCode) - } - - var release GitHubRelease - if err := json.NewDecoder(resp.Body).Decode(&release); err != nil { - return "", nil, fmt.Errorf("解析响应失败:%v", err) - } - - return release.TagName, release.Assets, nil -} - -func (s *sSystem) CheckUpdate() (err error) { - ctx := gctx.New() - latestVersion, assets, err := s.getLatestVersion() - if err != nil { - fmt.Printf("检查更新失败:%v\n", err) - return - } - - localVersion = gfile.GetContents(versionFile) - - if s.isNewVersion(localVersion, latestVersion) { - g.Log().Printf(ctx, "发现新版本:%s(当前版本:%s)", latestVersion, localVersion) - //拼接操作系统和架构(格式:OS_ARCH) - platform := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH) - //name := fmt.Sprintf("p2p_%s_%s.tar.gz", latestVersion, platform) - fmt.Println("下载链接:") - for _, asset := range assets { - if strings.Contains(fmt.Sprintf("_%s.", asset.Name), platform) { - fmt.Printf("- %s\n", asset.BrowserDownloadUrl) - - // 下载更新文件 - fileDownload, err2 := g.Client().Get(ctx, asset.BrowserDownloadUrl) - if err2 != nil { - return - } - updateFile := path.Join("download", asset.Name) - err = gfile.PutBytes(updateFile, fileDownload.ReadAll()) - - err = s.Update(ctx, updateFile) - if err != nil { - return - } - // 保存最新版本号到文件 - gfile.PutContents(versionFile, latestVersion) - break - } - } - } else { - fmt.Printf("当前已是最新版本:%s\n", localVersion) - } - return -}