diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 5bbec05..c4c78b4 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -7,9 +7,9 @@ on: tags: - v* paths-ignore: - - 'lankong_tools/**' + - 'lankong_tools/**' - '*.md' - - '.github/**' + - '.github/**' env: IMAGE_NAME: random-api-go @@ -19,9 +19,22 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout + - name: Checkout code uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.23' + + - name: Build for amd64 + run: | + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -o bin/amd64/random-api . + + - name: Build for arm64 + run: | + CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -a -installsuffix cgo -o bin/arm64/random-api . + - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -34,11 +47,11 @@ jobs: username: woodchen password: ${{ secrets.ACCESS_TOKEN }} - - name: Build and push + - name: Build and push multi-arch image uses: docker/build-push-action@v5 with: context: . - file: Dockerfile + file: Dockerfile.run push: true tags: woodchen/${{ env.IMAGE_NAME }}:latest platforms: linux/amd64,linux/arm64 @@ -53,8 +66,8 @@ jobs: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} - source: "public.zip" - target: "/tmp" + source: 'public.zip' + target: '/tmp' - name: Execute deployment commands uses: appleboy/ssh-action@master @@ -87,4 +100,4 @@ jobs: docker rm random-api-go || true # 启动容器 - docker compose -f /opt/1panel/docker/compose/random-api-go/docker-compose.yml up -d \ No newline at end of file + docker compose -f /opt/1panel/docker/compose/random-api-go/docker-compose.yml up -d diff --git a/Dockerfile.run b/Dockerfile.run new file mode 100644 index 0000000..134eefb --- /dev/null +++ b/Dockerfile.run @@ -0,0 +1,23 @@ +FROM --platform=$TARGETPLATFORM alpine:latest + +WORKDIR /root/ + +# 安装必要的包 +RUN apk --no-cache add ca-certificates tzdata tini + +# 创建日志目录并设置权限 +RUN mkdir -p /var/log/random-api && chmod 755 /var/log/random-api + +# 根据目标平台复制对应的二进制文件 +ARG TARGETARCH +COPY bin/${TARGETARCH}/random-api . +COPY public ./public +COPY public /tmp/public +COPY start.sh /start.sh +RUN chmod +x /start.sh + +EXPOSE 5003 + +# 使用 tini 作为初始化系统 +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["/start.sh"] diff --git a/services/csv_service.go b/services/csv_service.go index 1976c43..798ac61 100644 --- a/services/csv_service.go +++ b/services/csv_service.go @@ -28,11 +28,19 @@ func InitializeCSVService() error { return fmt.Errorf("failed to load CSV paths: %v", err) } - // 预加载所有CSV内容 + // 获取一个CSVPathsCache的副本,避免长时间持有锁 Mu.RLock() - defer Mu.RUnlock() - + pathsCopy := make(map[string]map[string]string) for prefix, suffixMap := range CSVPathsCache { + pathsCopy[prefix] = make(map[string]string) + for suffix, path := range suffixMap { + pathsCopy[prefix][suffix] = path + } + } + Mu.RUnlock() + + // 使用副本进行初始化 + for prefix, suffixMap := range pathsCopy { for suffix, csvPath := range suffixMap { selector, err := GetCSVContent(csvPath) if err != nil { @@ -113,51 +121,55 @@ func LoadCSVPaths() error { } func GetCSVContent(path string) (*models.URLSelector, error) { + log.Printf("开始获取CSV内容: %s", path) + Mu.RLock() selector, exists := csvCache[path] Mu.RUnlock() + if exists { + log.Printf("从缓存中获取到CSV内容: %s", path) return selector, nil } var fileContent []byte var err error - // 获取环境变量中的基础URL baseURL := os.Getenv(config.EnvBaseURL) if baseURL != "" { - // 如果设置了基础URL,构建完整的URL var fullURL string if strings.HasPrefix(baseURL, "http://") || strings.HasPrefix(baseURL, "https://") { - // 如果baseURL已经包含协议,直接使用 fullURL = utils.JoinURLPath(baseURL, path) } else { - // 如果没有协议,添加https:// fullURL = "https://" + utils.JoinURLPath(baseURL, path) } log.Printf("尝试从URL获取: %s", fullURL) - // 创建HTTP客户端 client := &http.Client{ Timeout: config.RequestTimeout, } resp, err := client.Get(fullURL) if err != nil { + log.Printf("HTTP请求失败: %v", err) return nil, fmt.Errorf("HTTP请求失败: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { + log.Printf("HTTP请求返回非200状态码: %d", resp.StatusCode) return nil, fmt.Errorf("HTTP请求返回非200状态码: %d", resp.StatusCode) } fileContent, err = io.ReadAll(resp.Body) if err != nil { + log.Printf("读取响应内容失败: %v", err) return nil, fmt.Errorf("读取响应内容失败: %w", err) } + + log.Printf("成功读取到CSV内容,长度: %d bytes", len(fileContent)) } else { // 如果没有设置基础URL,从本地文件读取 fullPath := filepath.Join("public", path) @@ -170,6 +182,8 @@ func GetCSVContent(path string) (*models.URLSelector, error) { } lines := strings.Split(string(fileContent), "\n") + log.Printf("CSV文件包含 %d 行", len(lines)) + uniqueURLs := make(map[string]bool) var fileArray []string for _, line := range lines { @@ -180,11 +194,14 @@ func GetCSVContent(path string) (*models.URLSelector, error) { } } + log.Printf("处理后得到 %d 个唯一URL", len(fileArray)) + selector = models.NewURLSelector(fileArray) Mu.Lock() csvCache[path] = selector Mu.Unlock() + log.Printf("CSV内容已缓存: %s", path) return selector, nil }