forked from
tangled.org/core
fork
Configure Feed
Select the types of activity you want to include in your feed.
Monorepo for Tangled
fork
Configure Feed
Select the types of activity you want to include in your feed.
1package knotserver
2
3import (
4 "context"
5 "fmt"
6 "net/http"
7
8 "github.com/urfave/cli/v3"
9 "tangled.sh/tangled.sh/core/api/tangled"
10 "tangled.sh/tangled.sh/core/hook"
11 "tangled.sh/tangled.sh/core/jetstream"
12 "tangled.sh/tangled.sh/core/knotserver/config"
13 "tangled.sh/tangled.sh/core/knotserver/db"
14 "tangled.sh/tangled.sh/core/knotserver/notifier"
15 "tangled.sh/tangled.sh/core/log"
16 "tangled.sh/tangled.sh/core/rbac"
17)
18
19func Command() *cli.Command {
20 return &cli.Command{
21 Name: "server",
22 Usage: "run a knot server",
23 Action: Run,
24 Description: `
25Environment variables:
26 KNOT_SERVER_SECRET (required)
27 KNOT_SERVER_HOSTNAME (required)
28 KNOT_SERVER_LISTEN_ADDR (default: 0.0.0.0:5555)
29 KNOT_SERVER_INTERNAL_LISTEN_ADDR (default: 127.0.0.1:5444)
30 KNOT_SERVER_DB_PATH (default: knotserver.db)
31 KNOT_SERVER_JETSTREAM_ENDPOINT (default: wss://jetstream1.us-west.bsky.network/subscribe)
32 KNOT_SERVER_DEV (default: false)
33 KNOT_REPO_SCAN_PATH (default: /home/git)
34 KNOT_REPO_README (comma-separated list)
35 KNOT_REPO_MAIN_BRANCH (default: main)
36 APPVIEW_ENDPOINT (default: https://tangled.sh)
37`,
38 }
39}
40
41func Run(ctx context.Context, cmd *cli.Command) error {
42 logger := log.FromContext(ctx)
43 iLogger := log.New("knotserver/internal")
44
45 c, err := config.Load(ctx)
46 if err != nil {
47 return fmt.Errorf("failed to load config: %w", err)
48 }
49
50 err = hook.Setup(
51 hook.WithScanPath(c.Repo.ScanPath),
52 hook.WithInternalApi(c.Server.InternalListenAddr),
53 )
54 if err != nil {
55 return fmt.Errorf("failed to setup hooks: %w", err)
56 }
57 logger.Info("successfully finished setting up hooks")
58
59 if c.Server.Dev {
60 logger.Info("running in dev mode, signature verification is disabled")
61 }
62
63 db, err := db.Setup(c.Server.DBPath)
64 if err != nil {
65 return fmt.Errorf("failed to load db: %w", err)
66 }
67
68 e, err := rbac.NewEnforcer(c.Server.DBPath)
69 if err != nil {
70 return fmt.Errorf("failed to setup rbac enforcer: %w", err)
71 }
72
73 e.E.EnableAutoSave(true)
74
75 jc, err := jetstream.NewJetstreamClient(c.Server.JetstreamEndpoint, "knotserver", []string{
76 tangled.PublicKeyNSID,
77 tangled.KnotMemberNSID,
78 }, nil, logger, db, true)
79 if err != nil {
80 logger.Error("failed to setup jetstream", "error", err)
81 }
82
83 notifier := notifier.New()
84
85 mux, err := Setup(ctx, c, db, e, jc, logger, ¬ifier)
86 if err != nil {
87 return fmt.Errorf("failed to setup server: %w", err)
88 }
89
90 imux := Internal(ctx, c, db, e, iLogger, ¬ifier)
91
92 logger.Info("starting internal server", "address", c.Server.InternalListenAddr)
93 go http.ListenAndServe(c.Server.InternalListenAddr, imux)
94
95 logger.Info("starting main server", "address", c.Server.ListenAddr)
96 logger.Error("server error", "error", http.ListenAndServe(c.Server.ListenAddr, mux))
97
98 return nil
99}