Skip to content

Commit 10e9472

Browse files
committed
first real commit
1 parent 5bfbade commit 10e9472

File tree

6 files changed

+219
-0
lines changed

6 files changed

+219
-0
lines changed

.github/workflows/main.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: build
2+
3+
on: push
4+
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- name: Check out the repo
10+
uses: actions/checkout@v4
11+
12+
- name: Set up QEMU
13+
uses: docker/setup-qemu-action@v3
14+
15+
- name: Set up Docker Buildx
16+
uses: docker/setup-buildx-action@v3
17+
18+
- name: Validate build configuration
19+
uses: docker/build-push-action@v6
20+
with:
21+
call: check
22+
23+
- name: "Login to GitHub Container Registry"
24+
uses: docker/login-action@v1
25+
with:
26+
registry: ghcr.io
27+
username: ${{github.actor}}
28+
password: ${{secrets.GITHUB_TOKEN}}
29+
30+
- name: Build
31+
uses: docker/build-push-action@v6
32+
with:
33+
context: .
34+
push: false
35+
tags: domnikl/pico-proxy
36+
platforms: linux/amd64,linux/arm64

.github/workflows/release.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Publish Docker image
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
jobs:
8+
push_to_registry:
9+
name: Push Docker image to Docker Hub
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Check out the repo
13+
uses: actions/checkout@v4
14+
15+
- name: "Login to GitHub Container Registry"
16+
uses: docker/login-action@v1
17+
with:
18+
registry: ghcr.io
19+
username: ${{github.actor}}
20+
password: ${{secrets.GITHUB_TOKEN}}
21+
22+
- name: Extract metadata (tags, labels) for Docker
23+
id: meta
24+
uses: docker/metadata-action@8e1d5461f02b7886d3c1a774bfbd873650445aa2
25+
with:
26+
images: domnikl/pico-proxy
27+
28+
- name: Set up QEMU
29+
uses: docker/setup-qemu-action@v3
30+
31+
- name: Set up Docker Buildx
32+
uses: docker/setup-buildx-action@v3
33+
34+
- name: Validate build configuration
35+
uses: docker/build-push-action@v6
36+
with:
37+
call: check
38+
39+
- name: Build
40+
uses: docker/build-push-action@v6
41+
with:
42+
context: .
43+
push: true
44+
tags: ${{ steps.meta.outputs.tags }}
45+
labels: ${{ steps.meta.outputs.labels }}
46+
platforms: linux/amd64,linux/arm64

Dockerfile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# syntax=docker/dockerfile:1
2+
3+
FROM golang:1.23.3
4+
LABEL org.opencontainers.image.source="https://github.com/domnikl/pico-proxy"
5+
6+
# Set destination for COPY
7+
WORKDIR /app
8+
9+
# Download Go modules
10+
COPY go.mod go.sum ./
11+
RUN go mod download
12+
13+
# Copy the source code. Note the slash at the end, as explained in
14+
# https://docs.docker.com/engine/reference/builder/#copy
15+
COPY cmd *.go ./
16+
17+
# Build
18+
RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-pico-proxy
19+
20+
# Optional:
21+
# To bind to a TCP port, runtime parameters must be supplied to the docker command.
22+
# But we can document in the Dockerfile what ports
23+
# the application is going to listen on by default.
24+
# https://docs.docker.com/engine/reference/builder/#expose
25+
EXPOSE 8080
26+
27+
# Run
28+
CMD ["/docker-pico-proxy"]

cmd/main.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"log"
7+
"net/http"
8+
"net/url"
9+
"os"
10+
"strings"
11+
)
12+
13+
var paths map[string]string
14+
15+
func extractPath(url *url.URL) string {
16+
parts := strings.Split(url.Path, "/")
17+
parts = parts[2:]
18+
19+
p := strings.Join(parts, "/")
20+
if url.RawQuery != "" {
21+
p += "?" + url.RawQuery
22+
}
23+
24+
return p
25+
}
26+
27+
func proxy(url string, w http.ResponseWriter, r *http.Request) {
28+
url = url + "/" + extractPath(r.URL)
29+
fmt.Printf("Proxying %s to %s\n", r.URL, url)
30+
31+
request, err := http.NewRequest("GET", url, r.Body)
32+
if err != nil {
33+
fmt.Println("Error creating request: " + err.Error())
34+
35+
http.Error(w, "Internal server error", http.StatusInternalServerError)
36+
return
37+
}
38+
39+
// Copy headers
40+
for name, value := range r.Header {
41+
request.Header.Set(name, value[0])
42+
}
43+
44+
resp, err := http.DefaultClient.Do(request)
45+
if err != nil {
46+
fmt.Printf("Error requesting %s: %s\n", url, err.Error())
47+
48+
http.Error(w, "Internal server error", http.StatusInternalServerError)
49+
return
50+
}
51+
52+
defer resp.Body.Close()
53+
54+
// Copy response body
55+
body, err := io.ReadAll(resp.Body)
56+
if err != nil {
57+
fmt.Printf("Error reading response from %s: %s\n", url, err.Error())
58+
59+
http.Error(w, "Internal server error", http.StatusInternalServerError)
60+
return
61+
}
62+
63+
w.WriteHeader(resp.StatusCode)
64+
65+
// Copy response headers
66+
for name, value := range resp.Header {
67+
w.Header().Set(name, value[0])
68+
}
69+
70+
w.Write(body)
71+
}
72+
73+
func handler(w http.ResponseWriter, r *http.Request) {
74+
path := strings.TrimSpace(r.URL.Path[1:])
75+
76+
for k, v := range paths {
77+
if strings.HasPrefix(path, k) {
78+
proxy(v, w, r)
79+
return
80+
}
81+
}
82+
83+
http.Error(w, "Not found", http.StatusNotFound)
84+
}
85+
86+
func main() {
87+
port := os.Getenv("PORT")
88+
if port == "" {
89+
port = "8080"
90+
}
91+
92+
fmt.Printf("Starting pico-proxy on port %s\n", port)
93+
94+
setupPaths := strings.Split(os.Getenv("PATHS"), ",")
95+
paths = make(map[string]string)
96+
97+
for _, path := range setupPaths {
98+
v := strings.SplitN(path, ":", 2)
99+
paths[v[0]] = v[1]
100+
101+
fmt.Printf("Path: %s, URL: %s\n", v[0], v[1])
102+
}
103+
104+
http.HandleFunc("GET /", handler)
105+
log.Fatal(http.ListenAndServe(":"+port, nil))
106+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/domnikl/pico-proxy
2+
3+
go 1.23.3

go.sum

Whitespace-only changes.

0 commit comments

Comments
 (0)