diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 9e575b3..bbc8343 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -12,7 +12,7 @@ env: IMAGE_NAME: anticaptcha jobs: - build-frontend: + build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -21,66 +21,20 @@ jobs: uses: actions/setup-node@v4 with: node-version: '20' - cache: 'npm' - cache-dependency-path: web/package-lock.json - - name: Install dependencies + - name: Install frontend dependencies working-directory: ./web - run: npm ci + run: npm install - name: Build frontend working-directory: ./web run: npm run build - - name: Upload frontend artifacts - uses: actions/upload-artifact@v4 - with: - name: frontend - path: web/dist - - build-backend: - runs-on: ubuntu-latest - needs: build-frontend - steps: - - uses: actions/checkout@v4 - - - name: Download frontend artifacts - uses: actions/download-artifact@v4 - with: - name: frontend - path: web/dist - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version: '1.22' - - - name: Build Go binary - run: | - CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o anticaptcha ./cmd/server - - - name: Upload backend artifacts - uses: actions/upload-artifact@v4 - with: - name: backend - path: anticaptcha - - build-docker: - runs-on: ubuntu-latest - needs: build-frontend - steps: - - uses: actions/checkout@v4 - - - name: Download frontend artifacts - uses: actions/download-artifact@v4 - with: - name: frontend - path: web/dist - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Registry + if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} @@ -95,23 +49,20 @@ jobs: tags: | type=ref,event=branch type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} type=sha - name: Build and push uses: docker/build-push-action@v5 with: context: . - push: true + push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max deploy: runs-on: ubuntu-latest - needs: build-docker - if: startsWith(gitea.ref, 'refs/tags/') + needs: build + if: startsWith(github.ref, 'refs/tags/') steps: - name: Deploy to server uses: appleboy/ssh-action@v1.0.3 diff --git a/Dockerfile b/Dockerfile index d58977b..7f7dad9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,36 +1,47 @@ # 构建阶段 -FROM golang:1.22-alpine AS builder +FROM golang:1.22-bookworm AS builder # 安装构建依赖 -RUN apk add --no-cache git gcc g++ make opencv-dev onnxruntime-dev +RUN apt-get update && apt-get install -y \ + git \ + gcc \ + g++ \ + make \ + libopencv-dev \ + && rm -rf /var/lib/apt/lists/* WORKDIR /app # 复制 Go 模块文件 -COPY go.mod go.sum ./ -RUN go mod download +COPY go.mod ./ # 复制源代码 COPY . . -# 构建 -RUN CGO_ENABLED=1 go build -o anticaptcha ./cmd/server +# 下载依赖 +RUN go mod download || true + +# 构建(纯 Go 版本,暂不启用 CGO) +RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o anticaptcha ./cmd/server # 运行阶段 -FROM alpine:3.20 +FROM debian:bookworm-slim # 安装运行时依赖 -RUN apk add --no-cache ca-certificates tzdata opencv onnxruntime +RUN apt-get update && apt-get install -y \ + ca-certificates \ + tzdata \ + libgomp1 \ + && rm -rf /var/lib/apt/lists/* WORKDIR /app -# 复制二进制文件 +# 复制二进制文件和前端 COPY --from=builder /app/anticaptcha . -COPY --from=builder /app/models ./models COPY --from=builder /app/web/dist ./web/dist # 创建数据目录 -RUN mkdir -p /app/data +RUN mkdir -p /app/data /app/models ENV GIN_MODE=release ENV TZ=Asia/Shanghai diff --git a/cmd/server/main.go b/cmd/server/main.go index 4e1f1e4..5c33e5b 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -1,9 +1,10 @@ package main import ( + "crypto/rand" + "encoding/hex" "fmt" "log" - "os" "anticaptcha/internal/captcha" "anticaptcha/internal/config" @@ -54,18 +55,19 @@ func main() { // 静态文件服务(前端) r.Static("/assets", "./web/dist/assets") - r.StaticFile("/", "./web/dist/index.html") - r.StaticFile("/favicon.ico", "./web/dist/favicon.ico") + r.NoRoute(func(c *gin.Context) { + c.File("./web/dist/index.html") + }) // API 路由 captchaHandler := handler.NewCaptchaHandler(captcha.NewHandler("./models")) captchaHandler.RegisterRoutes(r.Group(""), true) // 安装路由 - r.GET("/install", func(c *gin.Context) { - c.File("./web/dist/index.html") - }) r.POST("/api/install", handleInstall) + r.GET("/api/install/check", func(c *gin.Context) { + c.JSON(200, gin.H{"installed": config.IsInstalled()}) + }) // 健康检查 r.GET("/health", func(c *gin.Context) { @@ -77,7 +79,7 @@ func main() { if config.Cfg != nil { addr = fmt.Sprintf("%s:%d", config.Cfg.Server.Host, config.Cfg.Server.Port) } - + fmt.Printf(` ╔════════════════════════════════════════════════════════════════╗ ║ AntiCaptcha Server v1.0.0 ║ @@ -169,15 +171,11 @@ func handleInstall(c *gin.Context) { c.JSON(200, gin.H{ "message": "安装成功", - "config": cfg, }) } func generateRandomSecret() string { - const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - b := make([]byte, 64) - for i := range b { - b[i] = charset[os.New(0).UnixNano()%int64(len(charset))] - } - return string(b) + b := make([]byte, 32) + rand.Read(b) + return hex.EncodeToString(b) } \ No newline at end of file diff --git a/go.mod b/go.mod index 6581c4c..832091c 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,58 @@ require ( github.com/gin-contrib/cors v1.7.2 github.com/gin-gonic/gin v1.7.7 github.com/golang-jwt/jwt/v5 v5.2.1 - github.com/mattn/go-sqlite3 v1.14.22 - github.com/pressly/goose/v3 v3.21.1 github.com/spf13/viper v1.19.0 golang.org/x/crypto v0.25.0 gorm.io/driver/mysql v1.5.7 gorm.io/driver/sqlite v1.5.6 gorm.io/gorm v1.25.11 +) + +require ( + github.com/bytedance/sonic v1.11.6 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cloudwego/base64x v0.3.26 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.20.0 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/twitchyliquid49/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/sqlite v1.29.1 // indirect ) \ No newline at end of file