From 6762c822ab7ec803c4e87f5f1c18a3d8c0aee87a Mon Sep 17 00:00:00 2001 From: wood chen Date: Tue, 29 Oct 2024 23:00:16 +0800 Subject: [PATCH] first commit --- .github/workflows/docker-build.yml | 84 +++++++++++++++++++++++ Dockerfile | 13 ++++ data/config.json | 6 ++ main.go | 105 +++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 .github/workflows/docker-build.yml create mode 100644 Dockerfile create mode 100644 data/config.json create mode 100644 main.go diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 0000000..f918cfe --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,84 @@ +name: Build and Push Docker Image + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + arch: [amd64, arm64] + include: + - arch: amd64 + goarch: amd64 + - arch: arm64 + goarch: arm64 + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: '1.21' + + - name: Build binary + env: + GOOS: linux + GOARCH: ${{ matrix.goarch }} + CGO_ENABLED: 0 + run: | + go build -o proxy-go-${{ matrix.arch }} + + - name: Upload binary artifact + uses: actions/upload-artifact@v2 + with: + name: proxy-go-${{ matrix.arch }} + path: proxy-go-${{ matrix.arch }} + + docker: + needs: build + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Download all artifacts + uses: actions/download-artifact@v2 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: woodchen + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Get current date + id: date + run: echo "::set-output name=date::$(date +'%Y%m%d')" + + - name: Prepare binaries + run: | + chmod +x proxy-go-*/proxy-go-* + mv proxy-go-amd64/proxy-go-amd64 proxy-go-amd64/proxy-go + mv proxy-go-arm64/proxy-go-arm64 proxy-go-arm64/proxy-go + + - name: Build and push Docker images + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: | + woodchen/proxy-go:latest + ${{ secrets.DOCKERHUB_USERNAME }}/proxy-go:${{ steps.date.outputs.date }} + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..523b379 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM alpine:latest + +WORKDIR /app +COPY proxy-go /app/ +RUN mkdir -p /app/data && \ + chmod +x /app/proxy-go && \ + apk add --no-cache ca-certificates tzdata && \ + cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ + echo "Asia/Shanghai" > /etc/timezone + +EXPOSE 80 +VOLUME ["/app/data"] +ENTRYPOINT ["/app/proxy-go"] diff --git a/data/config.json b/data/config.json new file mode 100644 index 0000000..eafbc7e --- /dev/null +++ b/data/config.json @@ -0,0 +1,6 @@ +{ + "MAP":{ + "/path1": "https://path1.com/path/path/path", + "/path2": "https://path2.com" + } + } \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..4b32da9 --- /dev/null +++ b/main.go @@ -0,0 +1,105 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "os" + "strings" +) + +// Config 结构体用于解析配置文件 +type Config struct { + MAP map[string]string `json:"MAP"` +} + +func main() { + // 读取配置文件 + configFile, err := os.ReadFile("data/config.json") + if err != nil { + log.Fatal("Error reading config file:", err) + } + + // 解析配置文件 + var config Config + if err := json.Unmarshal(configFile, &config); err != nil { + log.Fatal("Error parsing config file:", err) + } + + // 创建 HTTP 处理函数 + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + // 处理根路径请求 + if r.URL.Path == "/" { + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, "Welcome to CZL proxy.") + return + } + + // 查找匹配的代理路径 + var matchedPrefix string + var targetBase string + for prefix, target := range config.MAP { + if strings.HasPrefix(r.URL.Path, prefix) { + matchedPrefix = prefix + targetBase = target + break + } + } + + // 如果没有匹配的路径,返回 404 + if matchedPrefix == "" { + http.NotFound(w, r) + return + } + + // 构建目标 URL + targetPath := strings.TrimPrefix(r.URL.Path, matchedPrefix) + targetURL := targetBase + targetPath + + // 创建新的请求 + proxyReq, err := http.NewRequest(r.Method, targetURL, r.Body) + if err != nil { + http.Error(w, "Error creating proxy request", http.StatusInternalServerError) + return + } + + // 复制原始请求的 header + for header, values := range r.Header { + for _, value := range values { + proxyReq.Header.Add(header, value) + } + } + + // 发送代理请求 + client := &http.Client{} + resp, err := client.Do(proxyReq) + if err != nil { + http.Error(w, "Error forwarding request", http.StatusBadGateway) + return + } + defer resp.Body.Close() + + // 复制响应 header + for header, values := range resp.Header { + for _, value := range values { + w.Header().Add(header, value) + } + } + + // 设置响应状态码 + w.WriteHeader(resp.StatusCode) + + // 复制响应体 + if _, err := io.Copy(w, resp.Body); err != nil { + log.Printf("Error copying response: %v", err) + } + }) + + // 启动服务器 + log.Println("Starting proxy server on :80") + if err := http.ListenAndServe(":80", nil); err != nil { + log.Fatal("Error starting server:", err) + } +}