Commit ·
a4468f1
1
Parent(s): d578104
init
Browse files- .gitignore +133 -0
- Dockerfile +33 -0
- README.md +1 -0
- app/app.go +57 -0
- app/http.go +44 -0
- app/kpl.go +92 -0
- cmd/main.go +11 -0
- conf/conf.go +89 -0
- go.mod +47 -0
- go.sum +126 -0
- internal/app/app.go +57 -0
- internal/app/http.go +44 -0
- internal/app/kpl.go +92 -0
- internal/conf/conf.go +89 -0
- pkg/logx/logx.go +262 -0
- pkg/logx/text_formater.go +114 -0
- pkg/mapx/mapx.go +203 -0
- pkg/mapx/mapx_test.go +43 -0
- pkg/pointer/pointer.go +32 -0
- pkg/tools/stack.go +29 -0
- pkg/tools/tools.go +49 -0
- release.bat +56 -0
.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 编译完成!
|