tangled
alpha
login
or
join now
willdot.net
/
at-shorter-url
27
fork
atom
A URL shortener service that uses ATProto to allow self hosting and ensuring the user owns their data
27
fork
atom
overview
issues
1
pulls
pipelines
Getting ready to deploy
willdot.net
5 months ago
2bf09b5c
a3f97ea9
+51
-6
6 changed files
expand all
collapse all
unified
split
.dockerignore
Dockerfile
cmd
atshorter
main.go
docker-compose.yaml
example.env
server.go
+4
.dockerignore
···
1
1
+
at-shorter
2
2
+
database.db
3
3
+
.env
4
4
+
example.env
+19
Dockerfile
···
1
1
+
FROM golang:latest AS builder
2
2
+
3
3
+
WORKDIR /app
4
4
+
5
5
+
COPY . .
6
6
+
RUN go mod download
7
7
+
8
8
+
COPY . .
9
9
+
10
10
+
RUN CGO_ENABLED=0 go build -o at-shorter .
11
11
+
12
12
+
FROM alpine:latest
13
13
+
14
14
+
RUN apk --no-cache add ca-certificates
15
15
+
16
16
+
WORKDIR /root/
17
17
+
COPY --from=builder /app/at-shorter .
18
18
+
19
19
+
CMD ["./at-shorter"]
+14
-4
cmd/atshorter/main.go
···
24
24
defaultServerAddr = "wss://jetstream.atproto.tools/subscribe"
25
25
httpClientTimeoutDuration = time.Second * 5
26
26
transportIdleConnTimeoutDuration = time.Second * 90
27
27
+
defaultPort = "8080"
27
28
)
28
29
29
30
func main() {
30
30
-
err := godotenv.Load(".env")
31
31
+
envLocation := os.Getenv("ENV_LOCATION")
32
32
+
if envLocation == "" {
33
33
+
envLocation = ".env"
34
34
+
}
35
35
+
36
36
+
err := godotenv.Load(envLocation)
31
37
if err != nil {
32
38
if !os.IsNotExist(err) {
33
39
log.Fatal("Error loading .env file")
···
54
60
defer db.Close()
55
61
56
62
var config oauth.ClientConfig
57
57
-
bind := ":8080"
63
63
+
port := os.Getenv("PORT")
64
64
+
if port == "" {
65
65
+
port = defaultPort
66
66
+
}
67
67
+
58
68
scopes := []string{
59
69
"atproto",
60
70
"repo:com.atshorter.shorturl?action=create",
···
63
73
}
64
74
if host == "" {
65
75
config = oauth.NewLocalhostConfig(
66
66
-
fmt.Sprintf("http://127.0.0.1%s/oauth-callback", bind),
76
76
+
fmt.Sprintf("http://127.0.0.1:%s/oauth-callback", port),
67
77
scopes,
68
78
)
69
79
slog.Info("configuring localhost OAuth client", "CallbackURL", config.CallbackURL)
···
83
93
},
84
94
}
85
95
86
86
-
server, err := atshorter.NewServer(host, 8080, db, oauthClient, httpClient)
96
96
+
server, err := atshorter.NewServer(host, port, db, oauthClient, httpClient)
87
97
if err != nil {
88
98
slog.Error("create new server", "error", err)
89
99
return
+11
docker-compose.yaml
···
1
1
+
services:
2
2
+
knot:
3
3
+
container_name: at-shorter
4
4
+
image: willdot/at-shorter:latest
5
5
+
environment:
6
6
+
ENV_LOCATION: "/data/at-shorter.env"
7
7
+
volumes:
8
8
+
- ./data:/app/data
9
9
+
ports:
10
10
+
- "3005:3005"
11
11
+
restart: always
+1
example.env
···
3
3
HOST="the host of the service such as https://my-url-shortner.com"
4
4
DATABASE_PATH="./"
5
5
JS_SERVER_ADDR="set to a different Jetstream instance"
6
6
+
PORT="3002"
+2
-2
server.go
···
40
40
mu sync.Mutex
41
41
}
42
42
43
43
-
func NewServer(host string, port int, store Store, oauthClient *oauth.ClientApp, httpClient *http.Client) (*Server, error) {
43
43
+
func NewServer(host string, port string, store Store, oauthClient *oauth.ClientApp, httpClient *http.Client) (*Server, error) {
44
44
sessionStore := sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))
45
45
46
46
homeTemplate, err := template.ParseFiles("./html/home.html")
···
83
83
mux.HandleFunc("GET /oauth-client-metadata.json", srv.serveClientMetadata)
84
84
mux.HandleFunc("GET /oauth-callback", srv.handleOauthCallback)
85
85
86
86
-
addr := fmt.Sprintf("0.0.0.0:%d", port)
86
86
+
addr := fmt.Sprintf("0.0.0.0:%s", port)
87
87
srv.httpserver = &http.Server{
88
88
Addr: addr,
89
89
Handler: mux,