tangled
alpha
login
or
join now
willdot.net
/
statusphere-go
20
fork
atom
An implementation of the ATProto statusphere example app but in Go
20
fork
atom
overview
issues
pulls
pipelines
Gitignore kicking my ass
willdot.net
10 months ago
1d39a11b
b94974b0
+113
1 changed file
expand all
collapse all
unified
split
cmd
main.go
+113
cmd/main.go
···
1
1
+
package main
2
2
+
3
3
+
import (
4
4
+
"context"
5
5
+
"errors"
6
6
+
"log"
7
7
+
"log/slog"
8
8
+
"net/http"
9
9
+
"os"
10
10
+
"os/signal"
11
11
+
"path"
12
12
+
"syscall"
13
13
+
"time"
14
14
+
15
15
+
"github.com/avast/retry-go/v4"
16
16
+
"github.com/joho/godotenv"
17
17
+
"github.com/willdot/statusphere-go"
18
18
+
"github.com/willdot/statusphere-go/database"
19
19
+
"github.com/willdot/statusphere-go/oauth"
20
20
+
)
21
21
+
22
22
+
const (
23
23
+
defaultServerAddr = "wss://jetstream.atproto.tools/subscribe"
24
24
+
httpClientTimeoutDuration = time.Second * 5
25
25
+
transportIdleConnTimeoutDuration = time.Second * 90
26
26
+
)
27
27
+
28
28
+
func main() {
29
29
+
err := godotenv.Load(".env")
30
30
+
if err != nil {
31
31
+
if !os.IsNotExist(err) {
32
32
+
log.Fatal("Error loading .env file")
33
33
+
}
34
34
+
}
35
35
+
36
36
+
host := os.Getenv("HOST")
37
37
+
if host == "" {
38
38
+
slog.Error("missing HOST env variable")
39
39
+
return
40
40
+
}
41
41
+
42
42
+
dbMountPath := os.Getenv("DATABASE_MOUNT_PATH")
43
43
+
if dbMountPath == "" {
44
44
+
slog.Error("DATABASE_MOUNT_PATH env not set")
45
45
+
return
46
46
+
}
47
47
+
48
48
+
dbFilename := path.Join(dbMountPath, "database.db")
49
49
+
db, err := database.New(dbFilename)
50
50
+
if err != nil {
51
51
+
slog.Error("create new database", "error", err)
52
52
+
return
53
53
+
}
54
54
+
defer db.Close()
55
55
+
56
56
+
httpClient := &http.Client{
57
57
+
Timeout: httpClientTimeoutDuration,
58
58
+
Transport: &http.Transport{
59
59
+
IdleConnTimeout: transportIdleConnTimeoutDuration,
60
60
+
},
61
61
+
}
62
62
+
63
63
+
oauthService, err := oauth.NewService(db, host, httpClient)
64
64
+
if err != nil {
65
65
+
slog.Error("creating new oauth service", "error", err)
66
66
+
return
67
67
+
}
68
68
+
69
69
+
server, err := statusphere.NewServer(host, 8080, db, oauthService, httpClient)
70
70
+
if err != nil {
71
71
+
slog.Error("create new server", "error", err)
72
72
+
return
73
73
+
}
74
74
+
75
75
+
signals := make(chan os.Signal, 1)
76
76
+
signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)
77
77
+
78
78
+
ctx, cancel := context.WithCancel(context.Background())
79
79
+
defer cancel()
80
80
+
81
81
+
go func() {
82
82
+
<-signals
83
83
+
cancel()
84
84
+
_ = server.Stop(context.Background())
85
85
+
}()
86
86
+
87
87
+
go consumeLoop(ctx, db)
88
88
+
89
89
+
server.Run()
90
90
+
}
91
91
+
92
92
+
func consumeLoop(ctx context.Context, db *database.DB) {
93
93
+
jsServerAddr := os.Getenv("JS_SERVER_ADDR")
94
94
+
if jsServerAddr == "" {
95
95
+
jsServerAddr = defaultServerAddr
96
96
+
}
97
97
+
98
98
+
consumer := statusphere.NewConsumer(jsServerAddr, slog.Default(), db)
99
99
+
100
100
+
err := retry.Do(func() error {
101
101
+
err := consumer.Consume(ctx)
102
102
+
if err != nil {
103
103
+
if errors.Is(err, context.Canceled) {
104
104
+
return nil
105
105
+
}
106
106
+
slog.Error("consume loop", "error", err)
107
107
+
return err
108
108
+
}
109
109
+
return nil
110
110
+
}, retry.UntilSucceeded()) // retry indefinitly until context canceled
111
111
+
slog.Error(err.Error())
112
112
+
slog.Warn("exiting consume loop")
113
113
+
}