23 Commits

Author SHA1 Message Date
2ba1bfa6e5 修改目录 2025-11-17 17:22:43 +08:00
e7f363ffad 更新库 2025-11-12 14:49:41 +08:00
0b6403c8d7 更新库 2025-11-11 14:52:29 +08:00
d3e5787508 不是用加速地址,容易失效 2025-11-10 19:03:39 +08:00
413df78f51 使用加速地址更新 2025-11-10 18:53:48 +08:00
07c5527243 更新库版本 2025-11-10 17:48:29 +08:00
乔焰阳
680d36e526 Simplify artifact handling in release workflow
Removed Gitea-specific artifact upload and download steps, simplifying the workflow.
2025-11-06 17:50:20 +08:00
乔焰阳
0a5432406a Refactor GitHub Actions workflow for releases
Updated GitHub Actions workflow to remove caching for Go installation and GF CLI, and adjusted artifact upload and download steps for GitHub and Gitea.
2025-11-06 17:20:34 +08:00
乔焰阳
7b16777411 Enhance release workflow with caching steps
Added caching for Go installation and GF CLI in the release workflow.
2025-11-06 16:03:04 +08:00
乔焰阳
69b4380e38 Refactor release workflow and update actions
Updated GitHub Actions workflow to remove container configuration and use the latest versions of actions.
2025-11-06 15:58:28 +08:00
乔焰阳
e856543529 Simplify release workflow by removing setup-go step
Removed setup-go step as Go environment is provided by the container image.
2025-11-06 15:50:06 +08:00
乔焰阳
4bed53dc16 Downgrade GitHub actions to v3 2025-11-04 16:12:48 +08:00
14f98a6009 去掉测试代码 2025-11-03 20:51:34 +08:00
610ae3aab2 github更新库修复无法对比版本的问题 2025-11-03 12:00:23 +08:00
4c4db5e9e2 服务端节点会给客户端追加公网ip 2025-10-31 17:51:20 +08:00
01cd7ae6e3 增加关闭窗口不退出程序 2025-10-31 17:34:38 +08:00
8d41c1ba62 实现了控制台启动后自动隐藏 2025-10-31 17:29:14 +08:00
22b4402737 去掉本地的更新逻辑,是有分离后的更新库 2025-10-31 15:50:59 +08:00
8b943b0cca 版本更新改为协程,预防拥堵主程序 2025-10-31 14:29:07 +08:00
03f762e910 更新完后需要修改文件可执行权限 2025-10-31 10:05:10 +08:00
84723248cd 删除更新的临时压缩包 2025-10-30 19:35:21 +08:00
d3f3687201 使用新的解压targz压缩的方法 2025-10-30 19:34:28 +08:00
63f5bef038 补充仓库缺少的基础配置文件 2025-10-30 18:49:13 +08:00
21 changed files with 248 additions and 701 deletions

View File

@@ -14,18 +14,24 @@ permissions:
jobs: jobs:
build: build:
# runs-on指定了运行作业的虚拟机环境类型
# 即使使用containerruns-on仍然是必要的配置
runs-on: ubuntu-latest runs-on: ubuntu-latest
# 移除容器配置以避免Docker Hub拉取超时问题
# 直接在GitHub托管的runner环境中执行任务
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4 # 使用最新稳定的v4版本
# GitHub Actions的runner环境通常已预装GoSetup Go步骤会处理版本管理
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.24.x' go-version: 'stable' # 使用最新稳定版本的Go无需手动更新版本号
- name: Install gf CLI - name: Install gf CLI
run: | run: |
# 直接下载GF CLI不使用缓存以避免超时问题
echo "Downloading GF CLI"
curl -L -o gf https://github.com/gogf/gf/releases/latest/download/gf_linux_amd64 curl -L -o gf https://github.com/gogf/gf/releases/latest/download/gf_linux_amd64
chmod +x gf chmod +x gf
mkdir -p "$HOME/bin" mkdir -p "$HOME/bin"
@@ -39,7 +45,7 @@ jobs:
run: gf build -ew -v "${{ github.ref_name }}" run: gf build -ew -v "${{ github.ref_name }}"
- name: Upload build artifacts - name: Upload build artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4 # 使用v4版本
with: with:
name: p2p-${{ github.ref_name }} name: p2p-${{ github.ref_name }}
path: | path: |
@@ -47,13 +53,17 @@ jobs:
release: release:
needs: build needs: build
# runs-on指定了运行作业的虚拟机环境类型
# 即使使用containerruns-on仍然是必要的配置
runs-on: ubuntu-latest runs-on: ubuntu-latest
# 移除容器配置以避免Docker Hub拉取超时问题
# 直接在GitHub托管的runner环境中执行任务
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4 # 使用v4版本
with: with:
name: p2p-${{ github.ref_name }} name: p2p-${{ github.ref_name }}
path: bin path: bin
@@ -84,7 +94,7 @@ jobs:
ls -al dist ls -al dist
- name: Create GitHub Release - name: Create GitHub Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v2 # 更新到最新稳定的v2版本
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ github.ref_name }} tag_name: ${{ github.ref_name }}

3
.gitignore vendored
View File

@@ -16,8 +16,9 @@ manifest/output/
temp/ temp/
temp.yaml temp.yaml
bin bin
**/config/config.yaml
v1.0.0/ v1.0.0/
config/local.yaml config/local.yaml
main.exe~ main.exe~
download/ download/
version.txt
internal/packed/build_pack_data.go

View File

@@ -1,11 +1 @@
package v1 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 {
}

View File

@@ -1,50 +1,42 @@
package main package main
import (
"image"
"os"
"github.com/icza/icox" // 替换为icox库
"github.com/nfnt/resize"
)
func main() { func main() {
// 1. 读取PNG文件 //// 1. 读取PNG文件
inputPath := "manifest/images/logo.png" // 输入PNG路径 //inputPath := "manifest/images/logo.png" // 输入PNG路径
outputPath := "manifest/images/favicon.ico" // 输出ICO路径 //outputPath := "manifest/images/favicon.ico" // 输出ICO路径
//
pngFile, err := os.Open(inputPath) //pngFile, err := os.Open(inputPath)
if err != nil { //if err != nil {
panic("无法打开PNG文件: " + err.Error()) // panic("无法打开PNG文件: " + err.Error())
} //}
defer pngFile.Close() //defer pngFile.Close()
//
// 2. 解码PNG为image.Image对象 //// 2. 解码PNG为image.Image对象
img, _, err := image.Decode(pngFile) //img, _, err := image.Decode(pngFile)
if err != nil { //if err != nil {
panic("PNG解码失败: " + err.Error()) // panic("PNG解码失败: " + err.Error())
} //}
//
// 3. 定义ICO需要包含的尺寸常见尺寸 //// 3. 定义ICO需要包含的尺寸常见尺寸
sizes := []uint{16, 32, 64, 128} // 可根据需求添加更多尺寸 //sizes := []uint{16, 32, 64, 128} // 可根据需求添加更多尺寸
var icoImages []image.Image //var icoImages []image.Image
//
// 4. 缩放图像到每个目标尺寸并收集 //// 4. 缩放图像到每个目标尺寸并收集
for _, size := range sizes { //for _, size := range sizes {
// 使用Lanczos3算法缩放高质量 // // 使用Lanczos3算法缩放高质量
resized := resize.Resize(size, size, img, resize.Lanczos3) // resized := resize.Resize(size, size, img, resize.Lanczos3)
icoImages = append(icoImages, resized) // icoImages = append(icoImages, resized)
} //}
//
// 5. 编码为ICO并写入文件关键修改使用icox.Encode //// 5. 编码为ICO并写入文件关键修改使用icox.Encode
icoFile, err := os.Create(outputPath) //icoFile, err := os.Create(outputPath)
if err != nil { //if err != nil {
panic("无法创建ICO文件: " + err.Error()) // panic("无法创建ICO文件: " + err.Error())
} //}
defer icoFile.Close() //defer icoFile.Close()
//
// icox.Encode直接支持多尺寸切片[]image.Image //// icox.Encode直接支持多尺寸切片[]image.Image
if err := icox.Encode(icoFile, icoImages); err != nil { //if err := icox.Encode(icoFile, icoImages); err != nil {
panic("ICO编码失败: " + err.Error()) // panic("ICO编码失败: " + err.Error())
} //}
} }

18
go.mod
View File

@@ -1,19 +1,19 @@
module github.com/ayflying/p2p module github.com/ayflying/p2p
go 1.24.0 go 1.24.8
toolchain go1.24.9
require ( require (
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9 github.com/ayflying/update-github-release v0.0.8
github.com/dop251/goja v0.0.0-20250630131328-58d95d85e994 github.com/dop251/goja v0.0.0-20250630131328-58d95d85e994
github.com/getlantern/systray v1.2.2 github.com/getlantern/systray v1.2.2
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.3 github.com/gogf/gf/v2 v2.9.5
github.com/gogf/gf/v2 v2.9.3
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.3 github.com/gorilla/websocket v1.5.3
github.com/libp2p/go-libp2p v0.43.0 github.com/libp2p/go-libp2p v0.43.0
github.com/libp2p/go-libp2p-kad-dht v0.35.1 github.com/libp2p/go-libp2p-kad-dht v0.35.1
github.com/minio/minio-go/v7 v7.0.95
github.com/multiformats/go-multiaddr v0.16.1 github.com/multiformats/go-multiaddr v0.16.1
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
) )
require ( require (
@@ -24,7 +24,6 @@ require (
github.com/clbanning/mxj/v2 v2.7.0 // indirect github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect
@@ -47,6 +46,7 @@ require (
github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/google/gopacket v1.1.19 // indirect github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/huin/goupnp v1.3.0 // indirect github.com/huin/goupnp v1.3.0 // indirect
@@ -81,7 +81,6 @@ require (
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/minio/crc64nvme v1.0.2 // indirect github.com/minio/crc64nvme v1.0.2 // indirect
github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.95 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect
@@ -97,7 +96,7 @@ require (
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
github.com/olekukonko/errors v1.1.0 // indirect github.com/olekukonko/errors v1.1.0 // indirect
github.com/olekukonko/ll v0.1.1 // indirect github.com/olekukonko/ll v0.1.1 // indirect
github.com/olekukonko/tablewriter v1.0.9 // indirect github.com/olekukonko/tablewriter v1.1.0 // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/philhofer/fwd v1.2.0 // indirect github.com/philhofer/fwd v1.2.0 // indirect
@@ -128,7 +127,6 @@ require (
github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.54.0 // indirect github.com/quic-go/quic-go v0.54.0 // indirect
github.com/quic-go/webtransport-go v0.9.0 // indirect github.com/quic-go/webtransport-go v0.9.0 // indirect
github.com/redis/go-redis/v9 v9.12.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/rs/xid v1.6.0 // indirect github.com/rs/xid v1.6.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect

24
go.sum
View File

@@ -10,21 +10,17 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9 h1:1ltqoej5GtaWF8jaiA49HwsZD459jqm9YFz9ZtMFpQA=
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/ayflying/update-github-release v0.0.8 h1:/ieMrqSi8novY9uSALPVSlWcBFdknDDhtgt08GKMojg=
github.com/ayflying/update-github-release v0.0.8/go.mod h1:9ctXuagiEKABWLaS4ocRCUcnN77jdYm7zir7NQ+rIeM=
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -42,8 +38,6 @@ github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dop251/goja v0.0.0-20250630131328-58d95d85e994 h1:aQYWswi+hRL2zJqGacdCZx32XjKYV8ApXFGntw79XAM= github.com/dop251/goja v0.0.0-20250630131328-58d95d85e994 h1:aQYWswi+hRL2zJqGacdCZx32XjKYV8ApXFGntw79XAM=
@@ -98,10 +92,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.3 h1:VTbeHq8XpBCWFIwBGmuBl+jP8AepULnpgNz8GPBKBRQ= github.com/gogf/gf/v2 v2.9.5 h1:1scfOdHbMP854oQaiLejl+eL+c4xfuvtWmmZiDJxbKs=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.3/go.mod h1:gcidgAYn4IWbx08QUThg7jw6bz3KklXI9/5zg8jnVHY= github.com/gogf/gf/v2 v2.9.5/go.mod h1:VUb5eyJKpvW77O/dXsbbLNO/Kjrg0UycIiq0lRiBjjo=
github.com/gogf/gf/v2 v2.9.3 h1:qjN4s55FfUzxZ1AE8vUHNDX3V0eIOUGXhF2DjRTVZQ4=
github.com/gogf/gf/v2 v2.9.3/go.mod h1:w6rcfD13SmO7FKI80k9LSLiSMGqpMYp50Nfkrrc2sEE=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
@@ -273,16 +265,14 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc=
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0=
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
github.com/olekukonko/ll v0.1.1 h1:9Dfeed5/Mgaxb9lHRAftLK9pVfYETvHn+If6lywVhJc= github.com/olekukonko/ll v0.1.1 h1:9Dfeed5/Mgaxb9lHRAftLK9pVfYETvHn+If6lywVhJc=
github.com/olekukonko/ll v0.1.1/go.mod h1:2dJo+hYZcJMLMbKwHEWvxCUbAOLc/CXWS9noET22Mdo= github.com/olekukonko/ll v0.1.1/go.mod h1:2dJo+hYZcJMLMbKwHEWvxCUbAOLc/CXWS9noET22Mdo=
github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8= github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
@@ -355,8 +345,6 @@ github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQB
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70= github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70=
github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao= github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao=
github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg=
github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=

37
internal/boot/boot.go Normal file
View File

@@ -0,0 +1,37 @@
package boot
import (
"context"
updateGithub "github.com/ayflying/update-github-release"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcron"
"github.com/gogf/gf/v2/os/gctx"
)
func Boot() {
getDev, _ := g.Cfg().GetWithEnv(gctx.New(), "dev")
if !getDev.Bool() {
url := "https://api.github.com/repos/ayflying/p2p/releases/latest"
var update = updateGithub.New(url)
// 每天0点检查更新
gcron.Add(gctx.New(), "0 0 0 * * *", func(ctx context.Context) {
err := update.CheckUpdate(true)
if err != nil {
g.Log().Errorf(ctx, "检查更新失败:%v", err)
}
})
go func() {
//在协程中检查更新,预防主程序阻塞
err := update.CheckUpdate(true)
if err != nil {
g.Log().Errorf(gctx.New(), "检查更新失败:%v", err)
}
}()
} else {
g.Log().Debugf(gctx.New(), "开发模式,不检查更新")
}
}

View File

@@ -5,9 +5,9 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/ayflying/p2p/internal/boot"
"github.com/ayflying/p2p/internal/consts" "github.com/ayflying/p2p/internal/consts"
"github.com/ayflying/p2p/internal/controller/p2p" "github.com/ayflying/p2p/internal/controller/p2p"
"github.com/ayflying/p2p/internal/controller/system"
"github.com/ayflying/p2p/internal/service" "github.com/ayflying/p2p/internal/service"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/net/ghttp"
@@ -18,7 +18,7 @@ import (
) )
func init() { func init() {
err := Main.AddCommand(&Main, &Debug, &Update) err := Main.AddCommand(&Main, &Debug)
if err != nil { if err != nil {
g.Log().Error(gctx.GetInitCtx(), err) g.Log().Error(gctx.GetInitCtx(), err)
return return
@@ -32,6 +32,10 @@ var (
Brief: "start http server", Brief: "start http server",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
g.Log().Debug(ctx, "开始执行main") g.Log().Debug(ctx, "开始执行main")
// 初始化服务器
boot.Boot()
Version, err := g.Cfg("hack").Get(ctx, "gfcli.build.version") Version, err := g.Cfg("hack").Get(ctx, "gfcli.build.version")
g.Log().Debugf(ctx, "当前启动的版本为:%v", Version) g.Log().Debugf(ctx, "当前启动的版本为:%v", Version)
@@ -69,7 +73,6 @@ var (
group.Middleware(ghttp.MiddlewareHandlerResponse) group.Middleware(ghttp.MiddlewareHandlerResponse)
group.Bind( group.Bind(
p2p.NewV1(), p2p.NewV1(),
system.NewV1(),
) )
}) })

View File

@@ -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
}}
)

View File

@@ -4,12 +4,4 @@
package system package system
import (
"github.com/ayflying/p2p/api/system"
)
type ControllerV1 struct{} type ControllerV1 struct{}
func NewV1() system.ISystemV1 {
return &ControllerV1{}
}

View File

@@ -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
}

View File

@@ -12,17 +12,29 @@ import (
"github.com/gogf/gf/v2/os/gcmd" "github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gfile" "github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gres"
) )
// 引入 Windows API 函数 // 引入 Windows API 函数
var ( var (
user32 = syscall.NewLazyDLL("user32.dll") user32 = syscall.NewLazyDLL("user32.dll")
kernel32 = syscall.NewLazyDLL("kernel32.dll") kernel32 = syscall.NewLazyDLL("kernel32.dll")
showWindow = user32.NewProc("ShowWindow") showWindow = user32.NewProc("ShowWindow")
getConsoleWnd = kernel32.NewProc("GetConsoleWindow") getConsoleWnd = kernel32.NewProc("GetConsoleWindow")
freeConsole = kernel32.NewProc("FreeConsole")
attachConsole = kernel32.NewProc("AttachConsole")
allocConsole = kernel32.NewProc("AllocConsole")
setConsoleCtrlHandler = kernel32.NewProc("SetConsoleCtrlHandler")
consoleCtrlHandler uintptr
)
const (
ctrlCloseEvent = 2
) )
func (s *sOS) start() { func (s *sOS) start() {
// 注册控制台关闭事件处理:点击叉叉仅隐藏控制台而不退出程序
s.setupConsoleCloseHandler()
// 系统托盘初始化(设置图标、右键菜单) // 系统托盘初始化(设置图标、右键菜单)
go systray.Run(s.onSystrayReady, s.onSystrayExit) go systray.Run(s.onSystrayReady, s.onSystrayExit)
@@ -30,9 +42,21 @@ func (s *sOS) start() {
// 系统托盘初始化(设置图标、右键菜单) // 系统托盘初始化(设置图标、右键菜单)
func (s *sOS) onSystrayReady() { func (s *sOS) onSystrayReady() {
//s.hideConsole() // s.hideConsole()
var iconByte []byte
if !gfile.Exists(s.systray.Icon) {
iconByte = gres.GetContent(s.systray.Icon)
gfile.PutBytes(s.systray.Icon, iconByte)
}
iconByte = gfile.GetBytes(s.systray.Icon)
//if gres.Contains(s.systray.Icon) {
// iconByte = gres.GetContent(s.systray.Icon)
// gfile.PutBytes(s.systray.Icon, iconByte)
//} else {
// iconByte = gfile.GetBytes(s.systray.Icon)
//}
iconByte := gfile.GetBytes(s.systray.Icon)
systray.SetIcon(iconByte) systray.SetIcon(iconByte)
systray.SetTitle(s.systray.Title) systray.SetTitle(s.systray.Title)
systray.SetTooltip(s.systray.Tooltip) systray.SetTooltip(s.systray.Tooltip)
@@ -46,6 +70,7 @@ func (s *sOS) onSystrayReady() {
select { select {
case <-mQuit.ClickedCh: case <-mQuit.ClickedCh:
systray.Quit() systray.Quit()
case <-mShow.ClickedCh: case <-mShow.ClickedCh:
// 显示窗口 // 显示窗口
s.showConsole() s.showConsole()
@@ -77,13 +102,12 @@ func (s *sOS) update(version, server string) {
// 隐藏控制台窗口 // 隐藏控制台窗口
func (s *sOS) hideConsole() { func (s *sOS) hideConsole() {
// 获取当前控制台窗口句柄 // 仅隐藏控制台窗口(保留现有缓冲区以便后续显示时保留历史日志)
hWnd, _, _ := getConsoleWnd.Call() hWnd, _, _ := getConsoleWnd.Call()
if hWnd == 0 { if hWnd != 0 {
return // 无控制台窗口如编译为GUI子系统时 // SW_HIDE = 0隐藏窗口
showWindow.Call(hWnd, 0)
} }
// SW_HIDE = 0隐藏窗口
showWindow.Call(hWnd, 0)
} }
// 显示控制台窗口 // 显示控制台窗口
@@ -91,8 +115,40 @@ func (s *sOS) showConsole() {
// 获取当前控制台窗口句柄 // 获取当前控制台窗口句柄
hWnd, _, _ := getConsoleWnd.Call() hWnd, _, _ := getConsoleWnd.Call()
if hWnd == 0 { if hWnd == 0 {
// 如果当前进程没有控制台,尝试附加到父进程控制台
// ATTACH_PARENT_PROCESS = (DWORD)-1
ret, _, _ := attachConsole.Call(uintptr(^uint32(0)))
if ret == 0 {
// 附加失败则分配一个新的控制台窗口
allocConsole.Call()
}
// 重新获取控制台窗口句柄
hWnd, _, _ = getConsoleWnd.Call()
}
if hWnd != 0 {
// SW_SHOW = 5显示窗口
showWindow.Call(hWnd, 5)
}
}
// 注册控制台关闭事件处理器,将关闭事件转换为隐藏行为
func (s *sOS) setupConsoleCloseHandler() {
if consoleCtrlHandler != 0 {
return return
} }
// SW_SHOW = 5显示窗口 consoleCtrlHandler = syscall.NewCallback(func(ctrlType uint32) uintptr {
showWindow.Call(hWnd, 5) if ctrlType == ctrlCloseEvent {
// 用户点击控制台窗口的关闭按钮(X):仅隐藏,不退出
hWnd, _, _ := getConsoleWnd.Call()
if hWnd != 0 {
// SW_HIDE = 0
showWindow.Call(hWnd, 0)
}
// 返回 TRUE 表示事件已处理,阻止默认终止行为
return 1
}
// 其他事件交由系统默认处理
return 0
})
setConsoleCtrlHandler.Call(consoleCtrlHandler, uintptr(1))
} }

View File

@@ -178,6 +178,7 @@ func (s *sP2P) register() error {
addrs[i] = addr.String() addrs[i] = addr.String()
} }
ports, _ := s.getLocalTCPPorts(s.client.host)
// 构建注册消息 // 构建注册消息
msg := GatewayMessage{ msg := GatewayMessage{
Type: MsgTypeRegister, Type: MsgTypeRegister,
@@ -185,6 +186,7 @@ func (s *sP2P) register() error {
Data: gjson.MustEncode(g.Map{ Data: gjson.MustEncode(g.Map{
"peer_id": s.client.host.ID().String(), "peer_id": s.client.host.ID().String(),
"addrs": addrs, "addrs": addrs,
"ports": ports,
}), }),
} }

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net"
"strings" "strings"
"time" "time"
@@ -104,6 +105,7 @@ func (s *sP2P) handleRegister(ctx context.Context, conn *websocket.Conn, msg *Ga
var data struct { var data struct {
PeerID string `json:"peer_id"` PeerID string `json:"peer_id"`
Addrs []string `json:"addrs"` Addrs []string `json:"addrs"`
Ports []int `json:"ports"`
} }
if err := json.Unmarshal(msg.Data, &data); err != nil { if err := json.Unmarshal(msg.Data, &data); err != nil {
@@ -111,18 +113,20 @@ func (s *sP2P) handleRegister(ctx context.Context, conn *websocket.Conn, msg *Ga
return return
} }
//// 追加公网ip // 追加公网ip
//publicIp, _, _ := net.SplitHostPort(conn.RemoteAddr().String()) publicIp, _, _ := net.SplitHostPort(conn.RemoteAddr().String())
//ParseIP := net.ParseIP(publicIp) ParseIP := net.ParseIP(publicIp)
//var ipType string var ipType string
//if ParseIP.To4() != nil { if ParseIP.To4() != nil {
// ipType = "ip4" ipType = "ip4"
//} else { } else {
// ipType = "ip6" ipType = "ip6"
//} }
//port2 := 53533 //port2 := 53533
//data.Addrs = append(data.Addrs, fmt.Sprintf("/%s/%s/tcp/%d", ipType, publicIp, port2)) for _, port2 := range data.Ports {
//data.Addrs = append(data.Addrs, fmt.Sprintf("/%s/%s/udp/%d/quic-v1", ipType, publicIp, port2)) data.Addrs = append(data.Addrs, fmt.Sprintf("/%s/%s/tcp/%d", ipType, publicIp, port2))
data.Addrs = append(data.Addrs, fmt.Sprintf("/%s/%s/udp/%d/quic-v1", ipType, publicIp, port2))
}
// 过滤回环地址 // 过滤回环地址
data.Addrs = s.filterLoopbackAddrs(data.Addrs) data.Addrs = s.filterLoopbackAddrs(data.Addrs)

View File

@@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"math/rand" "math/rand"
"net" "net"
"net/http"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -80,46 +79,6 @@ func init() {
ip, _ = service.P2P().GetIPv4PublicIP() ip, _ = service.P2P().GetIPv4PublicIP()
} }
// 获取公网IP并判断类型ipv4/ipv6
func (s *sP2P) getPublicIPAndType() (ip string, ipType string, err error) {
// 公网IP查询接口多个备用
client := http.Client{Timeout: 5 * time.Second}
for _, api := range ipAPIs {
resp, err := client.Get(api)
if err != nil {
continue
}
defer resp.Body.Close()
// 读取响应纯IP字符串
buf := make([]byte, 128)
n, err := resp.Body.Read(buf)
if err != nil {
continue
}
ip = strings.TrimSpace(string(buf[:n]))
if ip == "" {
continue
}
// 判断IP类型
parsedIP := net.ParseIP(ip)
if parsedIP == nil {
continue // 无效IP格式
}
if parsedIP.To4() != nil {
return ip, "ipv4", nil // IPv4
} else if parsedIP.To16() != nil {
return ip, "ipv6", nil // IPv6
}
}
return "", "", fmt.Errorf("所有公网IP查询接口均失败")
}
// 只获取IPv4公网IP过滤IPv6结果 // 只获取IPv4公网IP过滤IPv6结果
func (s *sP2P) GetIPv4PublicIP() (string, error) { func (s *sP2P) GetIPv4PublicIP() (string, error) {
ctx := gctx.New() ctx := gctx.New()

View File

@@ -1,87 +0,0 @@
package system
import "time"
type T struct {
Url string `json:"url"`
AssetsUrl string `json:"assets_url"`
UploadUrl string `json:"upload_url"`
HtmlUrl string `json:"html_url"`
Id int `json:"id"`
Author *Author `json:"author"`
NodeId string `json:"node_id"`
TagName string `json:"tag_name"`
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"`
Assets []*Assets
TarballUrl string `json:"tarball_url"`
ZipballUrl string `json:"zipball_url"`
Body string `json:"body"`
}
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"`
}

View File

@@ -1,14 +1,5 @@
package system package system
import (
"context"
"github.com/ayflying/p2p/internal/service"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcron"
"github.com/gogf/gf/v2/os/gctx"
)
type sSystem struct{} type sSystem struct{}
func New() *sSystem { func New() *sSystem {
@@ -16,25 +7,7 @@ func New() *sSystem {
} }
func init() { func init() {
service.RegisterSystem(New())
getDev, _ := g.Cfg().GetWithEnv(gctx.New(), "dev")
if !getDev.Bool() {
// 每天0点检查更新
gcron.Add(gctx.New(), "0 0 0 * * *", func(ctx context.Context) {
err := service.System().CheckUpdate()
if err != nil {
g.Log().Errorf(ctx, "检查更新失败:%v", err)
}
})
err := service.System().CheckUpdate()
if err != nil {
g.Log().Errorf(gctx.New(), "检查更新失败:%v", err)
}
} else {
g.Log().Debugf(gctx.New(), "开发模式,不检查更新")
}
} }
func (s *sSystem) Init() {} func (s *sSystem) Init() {}

View File

@@ -1,238 +0,0 @@
package system
import (
"context"
"encoding/json"
"fmt"
"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, runFile)
err = gcompress.UnGzipFile(gzFile, runFile)
}
if err != nil {
return
}
go func() {
log.Println("5秒后开始重启...")
time.Sleep(5 * time.Second)
if err = service.System().RestartSelf(); err != nil {
log.Fatalf("重启失败:%v", 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
}

View File

@@ -1 +1,2 @@
package packed package packed

View File

@@ -10,9 +10,8 @@ import (
"github.com/gogf/gf/v2/os/gcmd" "github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile" "github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
//步骤1加载驱动 //步骤1加载驱动
_ "github.com/gogf/gf/contrib/nosql/redis/v2" //_ "github.com/gogf/gf/contrib/nosql/redis/v2"
"github.com/ayflying/p2p/internal/cmd" "github.com/ayflying/p2p/internal/cmd"
"github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/os/gctx"
@@ -24,7 +23,7 @@ var (
func main() { func main() {
g.Log().Infof(ctx, "启动文件最后修改时间:%v", gtime.New(gfile.MTime(gcmd.GetArg(0).String())).String()) g.Log().Infof(ctx, "启动文件最后修改时间:%v", gtime.New(gfile.MTime(gcmd.GetArg(0).String())).String())
g.Dump("v1.0.0.2") //g.Dump("v1.0.0.2")
if ok := gfile.Exists("runtime"); !ok { if ok := gfile.Exists("runtime"); !ok {
gfile.Mkdir("runtime") gfile.Mkdir("runtime")

View File

@@ -0,0 +1,46 @@
module:
server: true
client: true
# https://goframe.org/docs/web/server-config-file-template
server:
address: "51888"
# openapiPath: "/api.json"
# swaggerPath: "/swagger"
dumpRouterMap: false
graceful: true
# https://goframe.org/docs/core/glog-config
logger:
level : "all"
stdout: true
# https://goframe.org/docs/core/gdb-config-file
database:
default:
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
redis:
default:
address: "ay.cname.com:6379"
db: 15
pass: "12345678"
cache:
address: "ay.cname.com:6379"
db: 15
pass: "12345678"
p2p:
list:
- host: "host.yunloli.cn"
port: 51888
ssl: false
ws: ws
- host: "ay.cname.com"
port: 51888
ssl: false
ws: ws