aurorax-neo commited on
Commit
a4468f1
1 Parent(s): d578104
.gitignore ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Node template
2
+ # Logs
3
+ logs
4
+ *.log
5
+ npm-debug.log*
6
+ yarn-debug.log*
7
+ yarn-error.log*
8
+ lerna-debug.log*
9
+ .pnpm-debug.log*
10
+
11
+ # Diagnostic reports (https://nodejs.org/api/report.html)
12
+ report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
13
+
14
+ # Runtime data
15
+ pids
16
+ *.pid
17
+ *.seed
18
+ *.pid.lock
19
+
20
+ # Directory for instrumented libs generated by jscoverage/JSCover
21
+ lib-cov
22
+
23
+ # Coverage directory used by tools like istanbul
24
+ coverage
25
+ *.lcov
26
+
27
+ # nyc test coverage
28
+ .nyc_output
29
+
30
+ # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
31
+ .grunt
32
+
33
+ # Bower dependency directory (https://bower.io/)
34
+ bower_components
35
+
36
+ # node-waf configuration
37
+ .lock-wscript
38
+
39
+ # Compiled binary addons (https://nodejs.org/api/addons.html)
40
+ build/Release
41
+
42
+ # Dependency directories
43
+ node_modules/
44
+ jspm_packages/
45
+
46
+ # Snowpack dependency directory (https://snowpack.dev/)
47
+ web_modules/
48
+
49
+ # TypeScript cache
50
+ *.tsbuildinfo
51
+
52
+ # Optional npm cache directory
53
+ .npm
54
+
55
+ # Optional eslint cache
56
+ .eslintcache
57
+
58
+ # Optional stylelint cache
59
+ .stylelintcache
60
+
61
+ # Microbundle cache
62
+ .rpt2_cache/
63
+ .rts2_cache_cjs/
64
+ .rts2_cache_es/
65
+ .rts2_cache_umd/
66
+
67
+ # Optional REPL history
68
+ .node_repl_history
69
+
70
+ # Output of 'npm pack'
71
+ *.tgz
72
+
73
+ # Yarn Integrity file
74
+ .yarn-integrity
75
+
76
+ # dotenv environment variable files
77
+ .env
78
+ .env.development.local
79
+ .env.test.local
80
+ .env.production.local
81
+ .env.local
82
+
83
+ # parcel-bundler cache (https://parceljs.org/)
84
+ .cache
85
+ .parcel-cache
86
+
87
+ # Next.js build output
88
+ .next
89
+ out
90
+
91
+ # Nuxt.js build / generate output
92
+ .nuxt
93
+ dist
94
+
95
+ # Gatsby files
96
+ .cache/
97
+ # Comment in the public line in if your project uses Gatsby and not Next.js
98
+ # https://nextjs.org/blog/next-9-1#public-directory-support
99
+ # public
100
+
101
+ # vuepress build output
102
+ .vuepress/dist
103
+
104
+ # vuepress v2.x temp and cache directory
105
+ .temp
106
+ .cache
107
+
108
+ # Docusaurus cache and generated files
109
+ .docusaurus
110
+
111
+ # Serverless directories
112
+ .serverless/
113
+
114
+ # FuseBox cache
115
+ .fusebox/
116
+
117
+ # DynamoDB Local files
118
+ .dynamodb/
119
+
120
+ # TernJS port file
121
+ .tern-port
122
+
123
+ # Stores VSCode versions used for testing VSCode extensions
124
+ .vscode-test
125
+
126
+ # yarn v2
127
+ .yarn/cache
128
+ .yarn/unplugged
129
+ .yarn/build-state.yml
130
+ .yarn/install-state.gz
131
+ .pnp.*
132
+
133
+ /config.json
Dockerfile ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Start with a base image containing Go runtime
2
+ FROM golang:1.22.0 AS builder
3
+
4
+ # Set the working directory inside the container
5
+ WORKDIR /app
6
+
7
+ # Copy the go mod and sum files
8
+ COPY go.mod go.sum ./
9
+
10
+ # Download dependencies
11
+ ENV GOPROXY=https://goproxy.cn,direct
12
+ RUN go mod download
13
+
14
+ # Copy the rest of the application's source code
15
+ COPY . .
16
+
17
+ # Build the Go app ensuring that the binary is statically linked
18
+ RUN CGO_ENABLED=0 go build -o /app/f99871322b15ff5007f0 /app/cmd/main.go
19
+
20
+ # Now use a smaller image to run the app
21
+ FROM alpine:latest
22
+
23
+ # Set the working directory in the new container
24
+ WORKDIR /app
25
+
26
+ # Copy the statically-linked binary into the new container
27
+ COPY --from=builder /app/f99871322b15ff5007f0 /app/f99871322b15ff5007f0
28
+
29
+ # This container exposes port 3040 to the outside world
30
+ EXPOSE 3040
31
+
32
+ # Run the binary.
33
+ CMD [ "/app/f99871322b15ff5007f0" ]
README.md CHANGED
@@ -6,6 +6,7 @@ colorTo: yellow
6
  sdk: docker
7
  pinned: false
8
  license: mit
 
9
  ---
10
 
11
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
6
  sdk: docker
7
  pinned: false
8
  license: mit
9
+ app_port: 3040
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app/app.go ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package app
2
+
3
+ import (
4
+ "context"
5
+ "kpl/internal/conf"
6
+ "kpl/pkg/logx"
7
+ "kpl/pkg/tools"
8
+ "os"
9
+ "time"
10
+ )
11
+
12
+ func Run(ctx context.Context) {
13
+ cleanUp := tools.Stack{}
14
+ ctx = logx.TagContext(ctx, "initial")
15
+ logx.Init(ctx)
16
+
17
+ // config
18
+ conf.Init(ctx)
19
+
20
+ // http
21
+ cleanUp.Push(Start(ctx))
22
+
23
+ // 提示 保活列表
24
+ logx.WithContext(ctx).Info("hgUrls: ")
25
+ for i, url := range conf.CONF.HgUrls {
26
+ logx.WithContext(ctx).Info(i, ": ", url)
27
+ }
28
+
29
+ logx.WithContext(ctx).Info("serv00s: ")
30
+ for i, serv00 := range conf.CONF.Serv00s {
31
+ logx.WithContext(ctx).Info(i, ": ", serv00.Username, "@", serv00.Host, ":", serv00.Port)
32
+ }
33
+
34
+ AsyncTimingTask(time.Duration(conf.CONF.HgIntervalSec)*time.Second, func() {
35
+ for _, url := range conf.CONF.HgUrls {
36
+ go DoGetRequest(ctx, url, conf.CONF.Proxy)
37
+ }
38
+ })
39
+
40
+ AsyncTimingTask(time.Duration(conf.CONF.Serv00IntervalSec)*time.Second, func() {
41
+ for _, serv00 := range conf.CONF.Serv00s {
42
+ go KplServ00(ctx, serv00.Username, serv00.Password, serv00.Host, serv00.Port, serv00.Cmd)
43
+ }
44
+ })
45
+
46
+ // Handle signals
47
+ {
48
+ exitCode := 1
49
+ exitCode = tools.HandleSignals(exitCode)
50
+ ctx = logx.TagContext(ctx, "cleanup")
51
+ for cleanUp.Next() {
52
+ cleanUp.Pop()(ctx)
53
+ }
54
+ time.Sleep(time.Second)
55
+ os.Exit(exitCode)
56
+ }
57
+ }
app/http.go ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package app
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+ "github.com/gin-gonic/gin"
7
+ "kpl/pkg/logx"
8
+ "net/http"
9
+ "time"
10
+ )
11
+
12
+ func Start(ctx context.Context) func(ctx context.Context) {
13
+ gin.SetMode(gin.ReleaseMode)
14
+
15
+ e := gin.New()
16
+
17
+ e.Use(gin.Recovery())
18
+
19
+ e.GET("/", func(ctx *gin.Context) {
20
+ ctx.String(http.StatusOK, "Hello World!")
21
+ })
22
+
23
+ srv := &http.Server{
24
+ Addr: ":3040",
25
+ Handler: e,
26
+ }
27
+
28
+ go func() {
29
+ logx.WithContext(ctx).Infof("http server initialized successfully at \u001B[35m%v\u001B[0m", srv.Addr)
30
+ if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
31
+ panic(err)
32
+ }
33
+ }()
34
+
35
+ return func(ctx context.Context) {
36
+ logx.WithContext(ctx).Info("http server shutdown.")
37
+ ctx, cancel := context.WithTimeout(ctx, time.Second*5)
38
+ srv.SetKeepAlivesEnabled(false)
39
+ if err := srv.Shutdown(ctx); err != nil {
40
+ logx.WithContext(ctx).Error(err.Error())
41
+ }
42
+ cancel()
43
+ }
44
+ }
app/kpl.go ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package app
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+ "github.com/aurorax-neo/tls_client_httpi"
7
+ "github.com/aurorax-neo/tls_client_httpi/tls_client"
8
+ "github.com/bogdanfinn/tls-client/profiles"
9
+ "golang.org/x/crypto/ssh"
10
+ "kpl/pkg/logx"
11
+ "time"
12
+ )
13
+
14
+ func AsyncTimingTask(nanosecond time.Duration, fun func()) {
15
+ go func() {
16
+ timerChan := time.After(nanosecond)
17
+ // 使用for循环阻塞等待定时器的信号
18
+ for {
19
+ // 通过select语句监听定时器通道和其他事件
20
+ select {
21
+ case <-timerChan:
22
+ fun()
23
+ // 重新设置定时器,以便下一次执行
24
+ timerChan = time.After(nanosecond)
25
+ }
26
+ time.Sleep(time.Millisecond * 100)
27
+ }
28
+ }()
29
+ }
30
+
31
+ // DoGetRequest 定义一个函数,用于发送GET请求
32
+ func DoGetRequest(ctx context.Context, rawUrl string, proxy string) {
33
+ opts := tls_client.NewClientOptions(5, profiles.Chrome_124)
34
+ client := tls_client.NewClient(opts)
35
+ _ = client.SetProxy(proxy)
36
+ res, err := client.Request(tls_client_httpi.GET, rawUrl, nil, nil, nil)
37
+ if err != nil {
38
+ logx.WithContext(ctx).Error(err)
39
+ return
40
+ }
41
+ logx.WithContext(ctx).Info(fmt.Sprint("GET ", rawUrl, " ", res.Status))
42
+ }
43
+
44
+ // KplServ00 serv00
45
+ func KplServ00(ctx context.Context, user string, password string, host string, port int, cmd string) {
46
+ // SSH 连接配置
47
+ sshConfig := &ssh.ClientConfig{
48
+ User: user,
49
+ Auth: []ssh.AuthMethod{
50
+ ssh.Password(password),
51
+ ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
52
+ answers = make([]string, len(questions))
53
+ for i := range questions {
54
+ answers[i] = password
55
+ }
56
+ return answers, nil
57
+ }),
58
+ },
59
+ HostKeyCallback: ssh.InsecureIgnoreHostKey(),
60
+ }
61
+
62
+ // 连接到远程服务器
63
+ client, err := ssh.Dial("tcp", fmt.Sprint(host, ":", port), sshConfig)
64
+ if err != nil {
65
+ logx.WithContext(ctx).Error(err)
66
+ return
67
+ }
68
+ defer func(client *ssh.Client) {
69
+ _ = client.Close()
70
+ }(client)
71
+
72
+ // 创建一个会话
73
+ session1, err := client.NewSession()
74
+ if err != nil {
75
+ logx.WithContext(ctx).Error(err)
76
+ return
77
+ }
78
+ // 关闭会话
79
+ defer func(session *ssh.Session) {
80
+ _ = session.Close()
81
+ }(session1)
82
+
83
+ // 执行命令
84
+ output1, err := session1.CombinedOutput(cmd)
85
+ if err != nil {
86
+ errMsg := fmt.Sprintf("%s@%s:%d - 执行命令失败: \n%s", user, host, port, err)
87
+ logx.WithContext(ctx).Error(errMsg)
88
+ } else {
89
+ msg := fmt.Sprintf("%s@%s:%d - 执行命令成功: \n%s", user, host, port, output1)
90
+ logx.WithContext(ctx).Info(msg)
91
+ }
92
+ }
cmd/main.go ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package main
2
+
3
+ import (
4
+ "context"
5
+ "kpl/internal/app"
6
+ )
7
+
8
+ func main() {
9
+ ctx := context.Background()
10
+ app.Run(ctx)
11
+ }
conf/conf.go ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package conf
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+ "github.com/joho/godotenv"
7
+ "kpl/pkg/logx"
8
+ "os"
9
+ "strconv"
10
+ )
11
+
12
+ var CONF = &conf{}
13
+
14
+ type Serv00 struct {
15
+ Host string
16
+ Port int
17
+ Username string
18
+ Password string
19
+ Cmd string
20
+ }
21
+
22
+ type conf struct {
23
+ Proxy string
24
+ Serv00s []Serv00
25
+ Serv00IntervalSec int
26
+ HgUrls []string
27
+ HgIntervalSec int
28
+ }
29
+
30
+ func Init(ctx context.Context) func(context.Context) {
31
+ _ = godotenv.Load()
32
+ index := 1
33
+ for {
34
+ url := os.Getenv(fmt.Sprint("HG_URL", index))
35
+ if url == "" {
36
+ break
37
+ }
38
+ CONF.HgUrls = append(CONF.HgUrls, url)
39
+ index++
40
+ }
41
+ index = 1
42
+ for {
43
+ host := os.Getenv(fmt.Sprint("SERV00_HOST", index))
44
+ username := os.Getenv(fmt.Sprint("SERV00_USERNAME", index))
45
+ password := os.Getenv(fmt.Sprint("SERV00_PASSWORD", index))
46
+ cmd := os.Getenv(fmt.Sprint("SERV00_CMD", index))
47
+ if host == "" {
48
+ break
49
+ }
50
+ if username == "" || password == "" || cmd == "" {
51
+ continue
52
+ }
53
+ CONF.Serv00s = append(CONF.Serv00s, Serv00{
54
+ Host: host,
55
+ Port: 22,
56
+ Username: username,
57
+ Password: password,
58
+ Cmd: cmd,
59
+ })
60
+ index++
61
+ }
62
+ CONF.Proxy = os.Getenv("PROXY")
63
+ hgIntervalSec := os.Getenv("HG_INTERVAL_SEC")
64
+ if hgIntervalSec == "" {
65
+ CONF.HgIntervalSec = 8
66
+ } else {
67
+ parseInt, err := strconv.ParseInt(hgIntervalSec, 10, 64)
68
+ if err != nil {
69
+ CONF.HgIntervalSec = 8
70
+ } else {
71
+ CONF.HgIntervalSec = int(parseInt)
72
+ }
73
+ }
74
+ serv00IntervalSec := os.Getenv("SERV00_INTERVAL_SEC")
75
+ if serv00IntervalSec == "" {
76
+ CONF.Serv00IntervalSec = 300
77
+ } else {
78
+ parseInt, err := strconv.ParseInt(serv00IntervalSec, 10, 64)
79
+ if err != nil {
80
+ CONF.Serv00IntervalSec = 300
81
+ } else {
82
+ CONF.Serv00IntervalSec = int(parseInt)
83
+ }
84
+ }
85
+ logx.WithContext(ctx).Infof("config loaded successfully")
86
+
87
+ return func(ctx context.Context) {
88
+ }
89
+ }
go.mod ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ module kpl
2
+
3
+ go 1.21
4
+
5
+ require (
6
+ github.com/aurorax-neo/tls_client_httpi v0.0.0-20240621113219-1c6faee7681b
7
+ github.com/bogdanfinn/tls-client v1.7.5
8
+ github.com/gin-gonic/gin v1.10.0
9
+ github.com/joho/godotenv v1.5.1
10
+ github.com/json-iterator/go v1.1.12
11
+ github.com/sirupsen/logrus v1.9.3
12
+ golang.org/x/crypto v0.24.0
13
+ )
14
+
15
+ require (
16
+ github.com/andybalholm/brotli v1.1.0 // indirect
17
+ github.com/bogdanfinn/fhttp v0.5.28 // indirect
18
+ github.com/bogdanfinn/utls v1.6.1 // indirect
19
+ github.com/bytedance/sonic v1.11.6 // indirect
20
+ github.com/bytedance/sonic/loader v0.1.1 // indirect
21
+ github.com/cloudflare/circl v1.3.9 // indirect
22
+ github.com/cloudwego/base64x v0.1.4 // indirect
23
+ github.com/cloudwego/iasm v0.2.0 // indirect
24
+ github.com/gabriel-vasile/mimetype v1.4.3 // indirect
25
+ github.com/gin-contrib/sse v0.1.0 // indirect
26
+ github.com/go-playground/locales v0.14.1 // indirect
27
+ github.com/go-playground/universal-translator v0.18.1 // indirect
28
+ github.com/go-playground/validator/v10 v10.20.0 // indirect
29
+ github.com/goccy/go-json v0.10.2 // indirect
30
+ github.com/klauspost/compress v1.17.9 // indirect
31
+ github.com/klauspost/cpuid/v2 v2.2.7 // indirect
32
+ github.com/leodido/go-urn v1.4.0 // indirect
33
+ github.com/mattn/go-isatty v0.0.20 // indirect
34
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
35
+ github.com/modern-go/reflect2 v1.0.2 // indirect
36
+ github.com/pelletier/go-toml/v2 v2.2.2 // indirect
37
+ github.com/quic-go/quic-go v0.45.0 // indirect
38
+ github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 // indirect
39
+ github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
40
+ github.com/ugorji/go/codec v1.2.12 // indirect
41
+ golang.org/x/arch v0.8.0 // indirect
42
+ golang.org/x/net v0.25.0 // indirect
43
+ golang.org/x/sys v0.21.0 // indirect
44
+ golang.org/x/text v0.16.0 // indirect
45
+ google.golang.org/protobuf v1.34.1 // indirect
46
+ gopkg.in/yaml.v3 v3.0.1 // indirect
47
+ )
go.sum ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
2
+ github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
3
+ github.com/aurorax-neo/tls_client_httpi v0.0.0-20240621113219-1c6faee7681b h1:PjtJ9Ljd2W6LRXQCZxzH47gxMVSBaOnrPbeBvTsib1g=
4
+ github.com/aurorax-neo/tls_client_httpi v0.0.0-20240621113219-1c6faee7681b/go.mod h1:IeKatJKJZ9jR4HO/rb3/OH6XpsOBBOFlw+zbxhGphPk=
5
+ github.com/bogdanfinn/fhttp v0.5.28 h1:G6thT8s8v6z1IuvXMUsX9QKy3ZHseTQTzxuIhSiaaAw=
6
+ github.com/bogdanfinn/fhttp v0.5.28/go.mod h1:oJiYPG3jQTKzk/VFmogH8jxjH5yiv2rrOH48Xso2lrE=
7
+ github.com/bogdanfinn/tls-client v1.7.5 h1:R1aTwe5oja5niLnQggzbWnzJEssw9n+3O4kR0H/Tjl4=
8
+ github.com/bogdanfinn/tls-client v1.7.5/go.mod h1:pQwF0eqfL0gf0mu8hikvu6deZ3ijSPruJDzEKEnnXjU=
9
+ github.com/bogdanfinn/utls v1.6.1 h1:dKDYAcXEyFFJ3GaWaN89DEyjyRraD1qb4osdEK89ass=
10
+ github.com/bogdanfinn/utls v1.6.1/go.mod h1:VXIbRZaiY/wHZc6Hu+DZ4O2CgTzjhjCg/Ou3V4r/39Y=
11
+ github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
12
+ github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
13
+ github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
14
+ github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
15
+ github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
16
+ github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
17
+ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
18
+ github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
19
+ github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
20
+ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
21
+ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
22
+ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
23
+ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
24
+ github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
25
+ github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
26
+ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
27
+ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
28
+ github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
29
+ github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
30
+ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
31
+ github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
32
+ github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
33
+ github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
34
+ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
35
+ github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
36
+ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
37
+ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
38
+ github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
39
+ github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
40
+ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
41
+ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
42
+ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
43
+ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
44
+ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
45
+ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
46
+ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
47
+ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
48
+ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
49
+ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
50
+ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
51
+ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
52
+ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
53
+ github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
54
+ github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
55
+ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
56
+ github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
57
+ github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
58
+ github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
59
+ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
60
+ github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
61
+ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
62
+ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
63
+ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
64
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
65
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
66
+ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
67
+ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
68
+ github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
69
+ github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
70
+ github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
71
+ github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
72
+ github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
73
+ github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
74
+ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
75
+ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
76
+ github.com/quic-go/quic-go v0.45.0 h1:OHmkQGM37luZITyTSu6ff03HP/2IrwDX1ZFiNEhSFUE=
77
+ github.com/quic-go/quic-go v0.45.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
78
+ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
79
+ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
80
+ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
81
+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
82
+ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
83
+ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
84
+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
85
+ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
86
+ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
87
+ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
88
+ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
89
+ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
90
+ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
91
+ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
92
+ github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 h1:YqAladjX7xpA6BM04leXMWAEjS0mTZ5kUU9KRBriQJc=
93
+ github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5/go.mod h1:2JjD2zLQYH5HO74y5+aE3remJQvl6q4Sn6aWA2wD1Ng=
94
+ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
95
+ github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
96
+ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
97
+ github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
98
+ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
99
+ golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
100
+ golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
101
+ golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
102
+ golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
103
+ golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
104
+ golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
105
+ golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
106
+ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
107
+ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
108
+ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
109
+ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
110
+ golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
111
+ golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
112
+ golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
113
+ golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
114
+ golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
115
+ golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
116
+ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
117
+ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
118
+ google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
119
+ google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
120
+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
121
+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
122
+ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
123
+ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
124
+ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
125
+ nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
126
+ rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
internal/app/app.go ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package app
2
+
3
+ import (
4
+ "context"
5
+ "kpl/internal/conf"
6
+ "kpl/pkg/logx"
7
+ "kpl/pkg/tools"
8
+ "os"
9
+ "time"
10
+ )
11
+
12
+ func Run(ctx context.Context) {
13
+ cleanUp := tools.Stack{}
14
+ ctx = logx.TagContext(ctx, "initial")
15
+ logx.Init(ctx)
16
+
17
+ // config
18
+ conf.Init(ctx)
19
+
20
+ // http
21
+ cleanUp.Push(Start(ctx))
22
+
23
+ // 提示 保活列表
24
+ logx.WithContext(ctx).Info("hgUrls: ")
25
+ for i, url := range conf.CONF.HgUrls {
26
+ logx.WithContext(ctx).Info(i, ": ", url)
27
+ }
28
+
29
+ logx.WithContext(ctx).Info("serv00s: ")
30
+ for i, serv00 := range conf.CONF.Serv00s {
31
+ logx.WithContext(ctx).Info(i, ": ", serv00.Username, "@", serv00.Host, ":", serv00.Port)
32
+ }
33
+
34
+ AsyncTimingTask(time.Duration(conf.CONF.HgIntervalSec)*time.Second, func() {
35
+ for _, url := range conf.CONF.HgUrls {
36
+ go DoGetRequest(ctx, url, conf.CONF.Proxy)
37
+ }
38
+ })
39
+
40
+ AsyncTimingTask(time.Duration(conf.CONF.Serv00IntervalSec)*time.Second, func() {
41
+ for _, serv00 := range conf.CONF.Serv00s {
42
+ go KplServ00(ctx, serv00.Username, serv00.Password, serv00.Host, serv00.Port, serv00.Cmd)
43
+ }
44
+ })
45
+
46
+ // Handle signals
47
+ {
48
+ exitCode := 1
49
+ exitCode = tools.HandleSignals(exitCode)
50
+ ctx = logx.TagContext(ctx, "cleanup")
51
+ for cleanUp.Next() {
52
+ cleanUp.Pop()(ctx)
53
+ }
54
+ time.Sleep(time.Second)
55
+ os.Exit(exitCode)
56
+ }
57
+ }
internal/app/http.go ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package app
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+ "github.com/gin-gonic/gin"
7
+ "kpl/pkg/logx"
8
+ "net/http"
9
+ "time"
10
+ )
11
+
12
+ func Start(ctx context.Context) func(ctx context.Context) {
13
+ gin.SetMode(gin.ReleaseMode)
14
+
15
+ e := gin.New()
16
+
17
+ e.Use(gin.Recovery())
18
+
19
+ e.GET("/", func(ctx *gin.Context) {
20
+ ctx.String(http.StatusOK, "Hello World!")
21
+ })
22
+
23
+ srv := &http.Server{
24
+ Addr: ":3040",
25
+ Handler: e,
26
+ }
27
+
28
+ go func() {
29
+ logx.WithContext(ctx).Infof("http server initialized successfully at \u001B[35m%v\u001B[0m", srv.Addr)
30
+ if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
31
+ panic(err)
32
+ }
33
+ }()
34
+
35
+ return func(ctx context.Context) {
36
+ logx.WithContext(ctx).Info("http server shutdown.")
37
+ ctx, cancel := context.WithTimeout(ctx, time.Second*5)
38
+ srv.SetKeepAlivesEnabled(false)
39
+ if err := srv.Shutdown(ctx); err != nil {
40
+ logx.WithContext(ctx).Error(err.Error())
41
+ }
42
+ cancel()
43
+ }
44
+ }
internal/app/kpl.go ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package app
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+ "github.com/aurorax-neo/tls_client_httpi"
7
+ "github.com/aurorax-neo/tls_client_httpi/tls_client"
8
+ "github.com/bogdanfinn/tls-client/profiles"
9
+ "golang.org/x/crypto/ssh"
10
+ "kpl/pkg/logx"
11
+ "time"
12
+ )
13
+
14
+ func AsyncTimingTask(nanosecond time.Duration, fun func()) {
15
+ go func() {
16
+ timerChan := time.After(nanosecond)
17
+ // 使用for循环阻塞等待定时器的信号
18
+ for {
19
+ // 通过select语句监听定时器通道和其他事件
20
+ select {
21
+ case <-timerChan:
22
+ fun()
23
+ // 重新设置定时器,以便下一次执行
24
+ timerChan = time.After(nanosecond)
25
+ }
26
+ time.Sleep(time.Millisecond * 100)
27
+ }
28
+ }()
29
+ }
30
+
31
+ // DoGetRequest 定义一个函数,用于发送GET请求
32
+ func DoGetRequest(ctx context.Context, rawUrl string, proxy string) {
33
+ opts := tls_client.NewClientOptions(5, profiles.Chrome_124)
34
+ client := tls_client.NewClient(opts)
35
+ _ = client.SetProxy(proxy)
36
+ res, err := client.Request(tls_client_httpi.GET, rawUrl, nil, nil, nil)
37
+ if err != nil {
38
+ logx.WithContext(ctx).Error(err)
39
+ return
40
+ }
41
+ logx.WithContext(ctx).Info(fmt.Sprint("GET ", rawUrl, " ", res.Status))
42
+ }
43
+
44
+ // KplServ00 serv00
45
+ func KplServ00(ctx context.Context, user string, password string, host string, port int, cmd string) {
46
+ // SSH 连接配置
47
+ sshConfig := &ssh.ClientConfig{
48
+ User: user,
49
+ Auth: []ssh.AuthMethod{
50
+ ssh.Password(password),
51
+ ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
52
+ answers = make([]string, len(questions))
53
+ for i := range questions {
54
+ answers[i] = password
55
+ }
56
+ return answers, nil
57
+ }),
58
+ },
59
+ HostKeyCallback: ssh.InsecureIgnoreHostKey(),
60
+ }
61
+
62
+ // 连接到远程服务器
63
+ client, err := ssh.Dial("tcp", fmt.Sprint(host, ":", port), sshConfig)
64
+ if err != nil {
65
+ logx.WithContext(ctx).Error(err)
66
+ return
67
+ }
68
+ defer func(client *ssh.Client) {
69
+ _ = client.Close()
70
+ }(client)
71
+
72
+ // 创建一个会话
73
+ session1, err := client.NewSession()
74
+ if err != nil {
75
+ logx.WithContext(ctx).Error(err)
76
+ return
77
+ }
78
+ // 关闭会话
79
+ defer func(session *ssh.Session) {
80
+ _ = session.Close()
81
+ }(session1)
82
+
83
+ // 执行命令
84
+ output1, err := session1.CombinedOutput(cmd)
85
+ if err != nil {
86
+ errMsg := fmt.Sprintf("%s@%s:%d - 执行命令失败: \n%s", user, host, port, err)
87
+ logx.WithContext(ctx).Error(errMsg)
88
+ } else {
89
+ msg := fmt.Sprintf("%s@%s:%d - 执行命令成功: \n%s", user, host, port, output1)
90
+ logx.WithContext(ctx).Info(msg)
91
+ }
92
+ }
internal/conf/conf.go ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package conf
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+ "github.com/joho/godotenv"
7
+ "kpl/pkg/logx"
8
+ "os"
9
+ "strconv"
10
+ )
11
+
12
+ var CONF = &conf{}
13
+
14
+ type Serv00 struct {
15
+ Host string
16
+ Port int
17
+ Username string
18
+ Password string
19
+ Cmd string
20
+ }
21
+
22
+ type conf struct {
23
+ Proxy string
24
+ Serv00s []Serv00
25
+ Serv00IntervalSec int
26
+ HgUrls []string
27
+ HgIntervalSec int
28
+ }
29
+
30
+ func Init(ctx context.Context) func(context.Context) {
31
+ _ = godotenv.Load()
32
+ index := 1
33
+ for {
34
+ url := os.Getenv(fmt.Sprint("HG_URL", index))
35
+ if url == "" {
36
+ break
37
+ }
38
+ CONF.HgUrls = append(CONF.HgUrls, url)
39
+ index++
40
+ }
41
+ index = 1
42
+ for {
43
+ host := os.Getenv(fmt.Sprint("SERV00_HOST", index))
44
+ username := os.Getenv(fmt.Sprint("SERV00_USERNAME", index))
45
+ password := os.Getenv(fmt.Sprint("SERV00_PASSWORD", index))
46
+ cmd := os.Getenv(fmt.Sprint("SERV00_CMD", index))
47
+ if host == "" {
48
+ break
49
+ }
50
+ if username == "" || password == "" || cmd == "" {
51
+ continue
52
+ }
53
+ CONF.Serv00s = append(CONF.Serv00s, Serv00{
54
+ Host: host,
55
+ Port: 22,
56
+ Username: username,
57
+ Password: password,
58
+ Cmd: cmd,
59
+ })
60
+ index++
61
+ }
62
+ CONF.Proxy = os.Getenv("PROXY")
63
+ hgIntervalSec := os.Getenv("HG_INTERVAL_SEC")
64
+ if hgIntervalSec == "" {
65
+ CONF.HgIntervalSec = 8
66
+ } else {
67
+ parseInt, err := strconv.ParseInt(hgIntervalSec, 10, 64)
68
+ if err != nil {
69
+ CONF.HgIntervalSec = 8
70
+ } else {
71
+ CONF.HgIntervalSec = int(parseInt)
72
+ }
73
+ }
74
+ serv00IntervalSec := os.Getenv("SERV00_INTERVAL_SEC")
75
+ if serv00IntervalSec == "" {
76
+ CONF.Serv00IntervalSec = 300
77
+ } else {
78
+ parseInt, err := strconv.ParseInt(serv00IntervalSec, 10, 64)
79
+ if err != nil {
80
+ CONF.Serv00IntervalSec = 300
81
+ } else {
82
+ CONF.Serv00IntervalSec = int(parseInt)
83
+ }
84
+ }
85
+ logx.WithContext(ctx).Infof("config loaded successfully")
86
+
87
+ return func(ctx context.Context) {
88
+ }
89
+ }
pkg/logx/logx.go ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package logx
2
+
3
+ import (
4
+ "context"
5
+ "encoding/json"
6
+ "fmt"
7
+ "github.com/sirupsen/logrus"
8
+ "os"
9
+ )
10
+
11
+ type (
12
+ Logger = logrus.Logger
13
+ Entry = logrus.Entry
14
+ Hook = logrus.Hook
15
+ Level = logrus.Level
16
+ )
17
+
18
+ func Init(ctx context.Context) {
19
+ SetLevel(logrus.DebugLevel)
20
+ SetFormatter(func() logrus.Formatter {
21
+ return &TextFormatter{}
22
+ }())
23
+ WithContext(ctx).Infof("application process in PID: %v", os.Getpid())
24
+ }
25
+
26
+ func SetLevel(level Level) {
27
+ logrus.SetLevel(level)
28
+ }
29
+
30
+ func SetFormatter(format logrus.Formatter) {
31
+ logrus.SetFormatter(format)
32
+ }
33
+
34
+ //
35
+ //func SetFormatter(format string) {
36
+ // switch format {
37
+ // case "json":
38
+ // logrus.SetFormatter(&logrus.JSONFormatter{})
39
+ // case "text":
40
+ // logrus.SetFormatter(&TextFormatter{})
41
+ // default:
42
+ // logrus.SetFormatter(&logrus.TextFormatter{})
43
+ // }
44
+ //}
45
+
46
+ func AddHook(hook Hook) {
47
+ logrus.AddHook(hook)
48
+ }
49
+
50
+ const (
51
+ TraceIdKey = "trace"
52
+ UserIDKey = "uid"
53
+ GuuIDKey = "guid"
54
+ SchoolIDKey = "school"
55
+ UsernameKey = "username"
56
+ TagKey = "tag"
57
+ StackKey = "stack"
58
+ )
59
+
60
+ type (
61
+ traceIdKey struct{}
62
+ userIDKey struct{}
63
+ guuIDKey struct{}
64
+ usernameKey struct{}
65
+ schoolIdKey struct{}
66
+ tagKey struct{}
67
+ stackKey struct{}
68
+ requestKey struct{}
69
+ responseKey struct{}
70
+ diff1Key struct{}
71
+ diff2Key struct{}
72
+ actionKey struct{}
73
+ )
74
+
75
+ func TraceIdContext(ctx context.Context, traceId string) context.Context {
76
+ return context.WithValue(ctx, traceIdKey{}, traceId)
77
+ }
78
+
79
+ func FromTraceIdContext(ctx context.Context) string {
80
+ if v := ctx.Value(traceIdKey{}); v != nil {
81
+ if s, ok := v.(string); ok {
82
+ return s
83
+ }
84
+ }
85
+ return ""
86
+ }
87
+
88
+ func UserIDContext(ctx context.Context, userId int) context.Context {
89
+ return context.WithValue(ctx, userIDKey{}, userId)
90
+ }
91
+
92
+ func FromUserIDContext(ctx context.Context) int {
93
+ if v := ctx.Value(userIDKey{}); v != nil {
94
+ if s, ok := v.(int); ok {
95
+ return s
96
+ }
97
+ }
98
+ return 0
99
+ }
100
+
101
+ func GuuIDContext(ctx context.Context, userId string) context.Context {
102
+ return context.WithValue(ctx, guuIDKey{}, userId)
103
+ }
104
+
105
+ func FromGuuIDContext(ctx context.Context) string {
106
+ if v := ctx.Value(guuIDKey{}); v != nil {
107
+ if s, ok := v.(string); ok {
108
+ return s
109
+ }
110
+ }
111
+ return ""
112
+ }
113
+
114
+ func SchoolIDContext(ctx context.Context, userId int) context.Context {
115
+ return context.WithValue(ctx, schoolIdKey{}, userId)
116
+ }
117
+
118
+ func FromSchoolIDContext(ctx context.Context) int {
119
+ if v := ctx.Value(schoolIdKey{}); v != nil {
120
+ if s, ok := v.(int); ok {
121
+ return s
122
+ }
123
+ }
124
+ return 0
125
+ }
126
+
127
+ func UsernameContext(ctx context.Context, username string) context.Context {
128
+ return context.WithValue(ctx, usernameKey{}, username)
129
+ }
130
+
131
+ func FromUsernameContext(ctx context.Context) string {
132
+ if v := ctx.Value(usernameKey{}); v != nil {
133
+ if s, ok := v.(string); ok {
134
+ return s
135
+ }
136
+ }
137
+ return ""
138
+ }
139
+
140
+ func TagContext(ctx context.Context, tag string) context.Context {
141
+ return context.WithValue(ctx, tagKey{}, tag)
142
+ }
143
+
144
+ func FromTagContext(ctx context.Context) string {
145
+ if v := ctx.Value(tagKey{}); v != nil {
146
+ if s, ok := v.(string); ok {
147
+ return s
148
+ }
149
+ }
150
+ return ""
151
+ }
152
+
153
+ func ActionContext(ctx context.Context, action string) context.Context {
154
+ return context.WithValue(ctx, actionKey{}, action)
155
+ }
156
+
157
+ func FromActionContext(ctx context.Context) string {
158
+ if v := ctx.Value(actionKey{}); v != nil {
159
+ if s, ok := v.(string); ok {
160
+ return s
161
+ }
162
+ }
163
+ return ""
164
+ }
165
+
166
+ func StackContext(ctx context.Context, stack error) context.Context {
167
+ return context.WithValue(ctx, stackKey{}, stack)
168
+ }
169
+
170
+ func FromStackContext(ctx context.Context) error {
171
+ if v := ctx.Value(tagKey{}); v != nil {
172
+ if e, ok := v.(error); ok {
173
+ return e
174
+ }
175
+ }
176
+ return nil
177
+ }
178
+
179
+ func RequestContext(ctx context.Context, data []byte) context.Context {
180
+ return context.WithValue(ctx, requestKey{}, string(data))
181
+ }
182
+
183
+ func FromRequestContext(ctx context.Context) string {
184
+ if v := ctx.Value(requestKey{}); v != "" {
185
+ if e, ok := v.(string); ok {
186
+ return e
187
+ }
188
+ }
189
+ return ""
190
+ }
191
+
192
+ func ResponseContext(ctx context.Context, data any) context.Context {
193
+ bts, _ := json.Marshal(&data)
194
+ return context.WithValue(ctx, responseKey{}, string(bts))
195
+ }
196
+
197
+ func FromResponseContext(ctx context.Context) string {
198
+ if v := ctx.Value(responseKey{}); v != "" {
199
+ if e, ok := v.(string); ok {
200
+ return e
201
+ }
202
+ }
203
+ return ""
204
+ }
205
+
206
+ func DiffContext(ctx context.Context, data1, data2 any) context.Context {
207
+ ctx = context.WithValue(ctx, diff1Key{}, data1)
208
+ ctx = context.WithValue(ctx, diff2Key{}, data2)
209
+ return ctx
210
+ }
211
+
212
+ func FromDiffContext(ctx context.Context) (any, any) {
213
+ return ctx.Value(diff1Key{}), ctx.Value(diff2Key{})
214
+ }
215
+
216
+ func WithContext(ctx context.Context) *Entry {
217
+ fields := logrus.Fields{}
218
+ if v := FromTraceIdContext(ctx); v != "" {
219
+ fields[TraceIdKey] = v
220
+ }
221
+
222
+ if v := FromUserIDContext(ctx); v != 0 {
223
+ fields[UserIDKey] = v
224
+ }
225
+
226
+ if v := FromGuuIDContext(ctx); v != "" {
227
+ fields[GuuIDKey] = v
228
+ }
229
+
230
+ if v := FromSchoolIDContext(ctx); v != 0 {
231
+ fields[SchoolIDKey] = v
232
+ }
233
+
234
+ if v := FromUsernameContext(ctx); v != "" {
235
+ fields[UsernameKey] = v
236
+ }
237
+
238
+ if v := FromTagContext(ctx); v != "" {
239
+ fields[TagKey] = v
240
+ }
241
+
242
+ if v := FromStackContext(ctx); v != nil {
243
+ fields[StackKey] = fmt.Sprintf("%+v", v)
244
+ }
245
+
246
+ return logrus.WithContext(ctx).WithFields(fields)
247
+ }
248
+
249
+ var (
250
+ Tracef = logrus.Tracef
251
+ Debugf = logrus.Debugf
252
+ Infof = logrus.Infof
253
+ Warnf = logrus.Warnf
254
+ Errorf = logrus.Errorf
255
+ Fatalf = logrus.Fatalf
256
+ Panicf = logrus.Panicf
257
+ Printf = logrus.Printf
258
+ SetOutput = logrus.SetOutput
259
+ SetReportCaller = logrus.SetReportCaller
260
+ StandardLogger = logrus.StandardLogger
261
+ ParseLevel = logrus.ParseLevel
262
+ )
pkg/logx/text_formater.go ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package logx
2
+
3
+ import (
4
+ "bytes"
5
+ "encoding/json"
6
+ "fmt"
7
+ "github.com/sirupsen/logrus"
8
+ "strings"
9
+ )
10
+
11
+ type TextFormatter struct {
12
+ }
13
+
14
+ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
15
+ //前景色 背景色
16
+ // 30 40 黑色
17
+ // 31 41 红色
18
+ // 32 42 绿色
19
+ // 33 43 黄色
20
+ // 34 44 蓝色
21
+ // 35 45 紫色
22
+ // 36 46 青色
23
+ // 37 47 白色
24
+ var color int
25
+ switch entry.Level {
26
+ case logrus.DebugLevel, logrus.TraceLevel:
27
+ color = 37
28
+ case logrus.WarnLevel:
29
+ color = 33
30
+ case logrus.ErrorLevel:
31
+ color = 31
32
+ case logrus.InfoLevel:
33
+ color = 36
34
+ case logrus.FatalLevel:
35
+ color = 41
36
+ case logrus.PanicLevel:
37
+ color = 44
38
+ default:
39
+ color = 36
40
+ }
41
+
42
+ var b *bytes.Buffer
43
+ if entry.Buffer != nil {
44
+ b = entry.Buffer
45
+ } else {
46
+ b = &bytes.Buffer{}
47
+ }
48
+
49
+ if entry.HasCaller() {
50
+ _, _ = fmt.Fprintf(b, "\u001B[%dmFunc\u001B[0m %v():%d\n", color, entry.Caller.Function, entry.Caller.Line)
51
+ }
52
+ //entry.Message = strings.TrimSuffix(entry.Message, "\n")
53
+ _, _ = fmt.Fprintf(b, "%s \x1b[%dm%s\x1b[0m", entry.Time.Format("2006-01-02 15:04:05:06"),
54
+ color, func() string {
55
+ level := strings.ToUpper(entry.Level.String())
56
+ if len(level) < 7 {
57
+ for i := len(level); i < 7; i++ {
58
+ level += " "
59
+ }
60
+ }
61
+ return level
62
+ }())
63
+
64
+ if tag, ok := entry.Data[TagKey]; ok {
65
+ // TAG:
66
+ _, _ = fmt.Fprintf(b, "\u001B[%dm%s\u001B[0m\t", 31, strings.ToUpper(tag.(string)))
67
+ delete(entry.Data, TagKey)
68
+ }
69
+
70
+ _, _ = fmt.Fprintf(b, " %-44s", entry.Message)
71
+
72
+ if schoolId, ok := entry.Data[SchoolIDKey]; ok {
73
+ _, _ = fmt.Fprintf(b, "[\u001B[%dm%v\u001B[0m]\t", 35, schoolId)
74
+ delete(entry.Data, SchoolIDKey)
75
+ }
76
+
77
+ {
78
+ userId, uidOk := entry.Data[UserIDKey]
79
+ username, unameOk := entry.Data[UsernameKey]
80
+ if uidOk && unameOk {
81
+ // USER_ID: USERNAME:
82
+ _, _ = fmt.Fprintf(b, "[\u001B[%dm%v(%v)\u001B[0m]\t", 36, username, userId)
83
+ delete(entry.Data, UserIDKey)
84
+ delete(entry.Data, UsernameKey)
85
+ }
86
+ }
87
+
88
+ if gUuid, ok := entry.Data[GuuIDKey]; ok {
89
+ // TAG:
90
+ _, _ = fmt.Fprintf(b, "\u001B[%dm%s\u001B[0m\t", 36, gUuid)
91
+ delete(entry.Data, GuuIDKey)
92
+ }
93
+
94
+ if traceId, ok := entry.Data[TraceIdKey]; ok {
95
+ // TRACE_ID:
96
+ _, _ = fmt.Fprintf(b, "\u001B[%dm%s\u001B[0m\t", 34, traceId)
97
+ delete(entry.Data, TraceIdKey)
98
+ }
99
+
100
+ if stack, ok := entry.Data[StackKey]; ok {
101
+ _, _ = fmt.Fprintf(b, "\u001B[%dm%s\u001B[0m\t", 33, stack)
102
+ delete(entry.Data, StackKey)
103
+ }
104
+
105
+ if len(entry.Data) > 0 {
106
+ // DATA:
107
+ var buf bytes.Buffer
108
+ _ = json.NewEncoder(&buf).Encode(&entry.Data)
109
+ _, _ = fmt.Fprintf(b, "\u001B[%dm%v\u001B[0m\t", 34, strings.TrimSuffix(buf.String(), "\n"))
110
+ }
111
+
112
+ b.WriteByte('\n')
113
+ return b.Bytes(), nil
114
+ }
pkg/mapx/mapx.go ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package mapx
2
+
3
+ import (
4
+ "encoding/json"
5
+ "fmt"
6
+ "net/url"
7
+ "reflect"
8
+ "sort"
9
+ "strconv"
10
+ "strings"
11
+ "time"
12
+ )
13
+
14
+ const dot = "."
15
+
16
+ type Mapx map[string]interface{}
17
+
18
+ func (m *Mapx) IsNil(key string) bool {
19
+ return m.Get(key) == nil
20
+ }
21
+
22
+ func (m *Mapx) GetString(key string) string {
23
+ return fmt.Sprintf("%v", m.Get(key))
24
+ }
25
+
26
+ func (m *Mapx) GetTime(key string) time.Time {
27
+ t, _ := time.ParseInLocation(time.RFC3339, m.GetString(key), time.Local)
28
+ return t
29
+ }
30
+
31
+ func (m *Mapx) GetInt(key string) int64 {
32
+ i, _ := strconv.ParseInt(m.GetString(key), 10, 64)
33
+ return i
34
+ }
35
+
36
+ func (m *Mapx) GetFloat(key string) float64 {
37
+ f, _ := strconv.ParseFloat(fmt.Sprintf("%v", m.Get(key)), 64)
38
+ return f
39
+ }
40
+
41
+ func (m *Mapx) GetBool(key string) bool {
42
+ b, _ := strconv.ParseBool(fmt.Sprintf("%v", m.Get(key)))
43
+ return b
44
+ }
45
+
46
+ func (m *Mapx) GetMapx(key string) *Mapx {
47
+ v, _ := m.Get(key).(map[string]interface{})
48
+ return (*Mapx)(&v)
49
+ }
50
+
51
+ func (m *Mapx) GetSlice(key string, fn func(item *Mapx, index int) bool) {
52
+ value := reflect.ValueOf(m.Get(key))
53
+ if value.Kind() != reflect.Slice {
54
+ return
55
+ }
56
+ for i := 0; i < value.Len(); i++ {
57
+ item := value.Index(i)
58
+ if item.Kind() != reflect.Invalid {
59
+ v, _ := item.Interface().(map[string]interface{})
60
+ if !fn((*Mapx)(&v), i) {
61
+ break
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ func (m *Mapx) Set(key string, val any) *Mapx {
68
+ (*m)[key] = val
69
+ return m
70
+ }
71
+
72
+ func (m *Mapx) Get(key string) any {
73
+ if m == nil {
74
+ return nil
75
+ }
76
+ var v any = map[string]interface{}(*m)
77
+ keys := strings.Split(key, dot)
78
+ for i := 0; i < len(keys); i++ {
79
+ if v == nil {
80
+ return nil
81
+ }
82
+ k := keys[i]
83
+ switch kind := reflect.TypeOf(v).Kind(); kind {
84
+ case reflect.Map:
85
+ _v := reflect.ValueOf(v).MapIndex(reflect.ValueOf(k))
86
+ if _v.Kind() != reflect.Invalid {
87
+ v = _v.Interface()
88
+ } else {
89
+ v = nil
90
+ }
91
+ case reflect.Slice:
92
+ if len(k) > 2 && k[0] == '[' && k[len(k)-1] == ']' {
93
+ idx, err := strconv.Atoi(k[1 : len(k)-1])
94
+ if err != nil {
95
+ return nil
96
+ }
97
+ _v := reflect.ValueOf(v).Index(idx)
98
+ if _v.Kind() != reflect.Invalid {
99
+ v = _v.Interface()
100
+ } else {
101
+ v = nil
102
+ }
103
+ }
104
+ case reflect.Struct:
105
+ _v := reflect.ValueOf(v).FieldByName(k)
106
+ if _v.Kind() != reflect.Invalid {
107
+ v = _v.Interface()
108
+ } else {
109
+ v = nil
110
+ }
111
+
112
+ case reflect.Ptr:
113
+ v = reflect.ValueOf(v).Elem().Interface()
114
+ i--
115
+ case reflect.Invalid:
116
+ return nil
117
+ default:
118
+ return nil
119
+ }
120
+ }
121
+ return v
122
+ }
123
+
124
+ func (m *Mapx) Remove(key string) {
125
+ delete(*m, key)
126
+ }
127
+
128
+ func (m *Mapx) Json() string {
129
+ b, _ := json.Marshal(&m)
130
+ return string(b)
131
+ }
132
+
133
+ func UnmarshalJSON(data []byte) (m *Mapx) {
134
+ _ = json.Unmarshal(data, &m)
135
+ return
136
+ }
137
+
138
+ // EncodeAliPaySignParams ("bar=baz&foo=quux") sorted by key.
139
+ func (m *Mapx) EncodeAliPaySignParams() string {
140
+ if m == nil {
141
+ return ""
142
+ }
143
+ var (
144
+ buf strings.Builder
145
+ keyList []string
146
+ )
147
+ for k := range *m {
148
+ keyList = append(keyList, k)
149
+ }
150
+ sort.Strings(keyList)
151
+ for _, k := range keyList {
152
+ if v := m.GetString(k); v != "" {
153
+ buf.WriteString(k)
154
+ buf.WriteByte('=')
155
+ buf.WriteString(v)
156
+ buf.WriteByte('&')
157
+ }
158
+ }
159
+ if buf.Len() <= 0 {
160
+ return ""
161
+ }
162
+ return buf.String()[:buf.Len()-1]
163
+ }
164
+
165
+ // EncodeURLParams ("bar=baz&foo=quux") sorted by key.
166
+ func (m *Mapx) EncodeURLParams() string {
167
+ if m == nil {
168
+ return ""
169
+ }
170
+ var (
171
+ buf strings.Builder
172
+ keys []string
173
+ )
174
+ for k := range *m {
175
+ keys = append(keys, k)
176
+ }
177
+ sort.Strings(keys)
178
+ for _, k := range keys {
179
+ if v := m.GetString(k); v != "" {
180
+ buf.WriteString(url.QueryEscape(k))
181
+ buf.WriteByte('=')
182
+ buf.WriteString(url.QueryEscape(v))
183
+ buf.WriteByte('&')
184
+ }
185
+ }
186
+ if buf.Len() <= 0 {
187
+ return ""
188
+ }
189
+ return buf.String()[:buf.Len()-1]
190
+ }
191
+
192
+ func (m *Mapx) ValidateEmpty(keys ...string) error {
193
+ var emptyKeys []string
194
+ for _, k := range keys {
195
+ if m.IsNil(k) {
196
+ emptyKeys = append(emptyKeys, k)
197
+ }
198
+ }
199
+ if len(emptyKeys) > 0 {
200
+ return fmt.Errorf("[miss param error], %v", strings.Join(emptyKeys, ", "))
201
+ }
202
+ return nil
203
+ }
pkg/mapx/mapx_test.go ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package mapx
2
+
3
+ import (
4
+ "fmt"
5
+ "testing"
6
+ )
7
+
8
+ func TestMapx(t *testing.T) {
9
+ mapx := Mapx{
10
+ "string": "abc",
11
+ "int": 1234,
12
+ "float": 12.34,
13
+ "slice": []any{
14
+ "a",
15
+ map[string]any{
16
+ "aa": map[string]interface{}{
17
+ "qwe": 123,
18
+ },
19
+ },
20
+ "c",
21
+ },
22
+ "map": map[string]any{
23
+ "map": map[string]any{
24
+ "bool": true,
25
+ "aa": map[string]interface{}{
26
+ "qwe": 123,
27
+ },
28
+ },
29
+ },
30
+ "m2": Mapx{
31
+ //"a": model.PayOrder{OrderNo: "1234"},
32
+ //"b": &model.PayOrder{OrderNo: "123444"},
33
+ },
34
+ }
35
+
36
+ //v := mapx.ListByIDs("map.map.aa.qwe")
37
+ //v := mapx.ListByIDs("slice.[1].aa.qwe")
38
+ v := mapx.Get("m2.b.OrderNo")
39
+ //v := mapx.ListByIDs("int")
40
+ //vv := v.(int)
41
+ fmt.Printf("type:%T value:%v\n", v, v)
42
+
43
+ }
pkg/pointer/pointer.go ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package pointer
2
+
3
+ import "reflect"
4
+
5
+ func To[T any](v T) *T {
6
+ vo := reflect.ValueOf(v)
7
+ for {
8
+ if vo.Kind() == reflect.Ptr {
9
+ vo = vo.Elem()
10
+ } else {
11
+ break
12
+ }
13
+ }
14
+ if vo.IsZero() {
15
+ return nil
16
+ }
17
+
18
+ return &v
19
+ }
20
+
21
+ func Take[T any](v *T) T {
22
+ if v == nil {
23
+ t := reflect.TypeOf(v)
24
+ _v := reflect.New(t)
25
+ for t.Kind() == reflect.Ptr {
26
+ t = t.Elem()
27
+ _v = _v.Elem()
28
+ }
29
+ return _v.Interface().(T)
30
+ }
31
+ return *v
32
+ }
pkg/tools/stack.go ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package tools
2
+
3
+ import (
4
+ "context"
5
+ "sync"
6
+ )
7
+
8
+ type Stack struct {
9
+ sync.Mutex
10
+ items []func(context.Context)
11
+ }
12
+
13
+ func (s *Stack) Pop() func(context.Context) {
14
+ s.Lock()
15
+ defer s.Unlock()
16
+ item := s.items[len(s.items)-1]
17
+ s.items = s.items[:len(s.items)-1]
18
+ return item
19
+ }
20
+
21
+ func (s *Stack) Push(item func(context.Context)) {
22
+ s.Lock()
23
+ defer s.Unlock()
24
+ s.items = append(s.items, item)
25
+ }
26
+
27
+ func (s *Stack) Next() bool {
28
+ return len(s.items) > 0
29
+ }
pkg/tools/tools.go ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package tools
2
+
3
+ import (
4
+ jsoniter "github.com/json-iterator/go"
5
+ "os"
6
+ "os/signal"
7
+ "syscall"
8
+ )
9
+
10
+ func HandleSignals(exitCode int) int {
11
+ s := make(chan os.Signal)
12
+ signal.Notify(s, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
13
+ EXIT:
14
+ for {
15
+ switch <-s {
16
+ case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
17
+ exitCode = 0
18
+ break EXIT
19
+ case syscall.SIGHUP:
20
+ default:
21
+ break EXIT
22
+ }
23
+ }
24
+ return exitCode
25
+ }
26
+
27
+ // Struct2Bytes 将结构体转换为字节数组
28
+ func Struct2Bytes(v interface{}) ([]byte, error) {
29
+ // 创建一个jsonIter的Encoder
30
+ configCompatibleWithStandardLibrary := jsoniter.ConfigCompatibleWithStandardLibrary
31
+ // 将结构体转换为JSON文本并保持顺序
32
+ bytes_, err := configCompatibleWithStandardLibrary.Marshal(v)
33
+ if err != nil {
34
+ return nil, err
35
+ }
36
+ return bytes_, nil
37
+ }
38
+
39
+ // Bytes2Struct 将字节数组转换为结构体
40
+ func Bytes2Struct(data []byte, v interface{}) error {
41
+ // 创建一个jsonIter的Decoder
42
+ configCompatibleWithStandardLibrary := jsoniter.ConfigCompatibleWithStandardLibrary
43
+ // 将JSON字节数组解码为结构体
44
+ err := configCompatibleWithStandardLibrary.Unmarshal(data, v)
45
+ if err != nil {
46
+ return err
47
+ }
48
+ return nil
49
+ }
release.bat ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @echo off
2
+ SETLOCAL
3
+
4
+ REM 指定编码为 UTF-8
5
+ chcp 65001
6
+
7
+ REM 设置要生成的可执行文件的名称
8
+ set OUTPUT_NAME=hg_kpl
9
+
10
+ REM 设置 Go 源文件的名称
11
+ SET GOFILE=cmd/main.go
12
+
13
+ REM 设置输出目录
14
+ SET OUTPUTDIR=target
15
+
16
+ REM 确保输出目录存在
17
+ IF NOT EXIST %OUTPUTDIR% MKDIR %OUTPUTDIR%
18
+
19
+ REM 编译为 Windows/amd64
20
+ echo 开始编译 Windows/amd64
21
+ SET GOOS=windows
22
+ SET GOARCH=amd64
23
+ go build -o %OUTPUTDIR%/%OUTPUT_NAME%_windows_amd64.exe %GOFILE%
24
+ echo 编译完成 Windows/amd64
25
+
26
+ REM 编译为 Windows/386
27
+ echo 开始编译 Windows/386
28
+ SET GOOS=windows
29
+ SET GOARCH=386
30
+ go build -o %OUTPUTDIR%/%OUTPUT_NAME%_windows_386.exe %GOFILE%
31
+ echo 编译完成 Windows/386
32
+
33
+ REM 编译为 Linux/amd64
34
+ echo 开始编译 Linux/amd64
35
+ SET GOOS=linux
36
+ SET GOARCH=amd64
37
+ go build -o %OUTPUTDIR%/%OUTPUT_NAME%_linux_amd64 %GOFILE%
38
+ echo 编译完成 Linux/amd64
39
+
40
+ REM 编译为 macOS/amd64
41
+ echo 开始编译 macOS/amd64
42
+ SET GOOS=darwin
43
+ SET GOARCH=amd64
44
+ go build -o %OUTPUTDIR%/%OUTPUT_NAME%_macos_amd64 %GOFILE%
45
+ echo 编译完成 macOS/amd64
46
+
47
+ REM 编译为 freebsd/amd64
48
+ echo 开始编译 freebsd/amd64
49
+ SET GOOS=freebsd
50
+ SET GOARCH=amd64
51
+ go build -o %OUTPUTDIR%/%OUTPUT_NAME%_freebsd_amd64 %GOFILE%
52
+ echo 编译完成 freebsd/amd64
53
+
54
+ REM 结束批处理脚本
55
+ ENDLOCAL
56
+ echo 编译完成!