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 "log/slog"
7 "net/http"
8
9 "github.com/go-chi/chi/v5"
10 "github.com/sotangled/tangled/jetstream"
11 "github.com/sotangled/tangled/knotserver/config"
12 "github.com/sotangled/tangled/knotserver/db"
13 "github.com/sotangled/tangled/rbac"
14)
15
16const (
17 ThisServer = "thisserver" // resource identifier for rbac enforcement
18)
19
20type Handle struct {
21 c *config.Config
22 db *db.DB
23 jc *jetstream.JetstreamClient
24 e *rbac.Enforcer
25 l *slog.Logger
26
27 // init is a channel that is closed when the knot has been initailized
28 // i.e. when the first user (knot owner) has been added.
29 init chan struct{}
30 knotInitialized bool
31}
32
33func Setup(ctx context.Context, c *config.Config, db *db.DB, e *rbac.Enforcer, jc *jetstream.JetstreamClient, l *slog.Logger) (http.Handler, error) {
34 r := chi.NewRouter()
35
36 h := Handle{
37 c: c,
38 db: db,
39 e: e,
40 l: l,
41 jc: jc,
42 init: make(chan struct{}),
43 }
44
45 err := e.AddDomain(ThisServer)
46 if err != nil {
47 return nil, fmt.Errorf("failed to setup enforcer: %w", err)
48 }
49
50 err = h.jc.StartJetstream(ctx, h.processMessages)
51 if err != nil {
52 return nil, fmt.Errorf("failed to start jetstream: %w", err)
53 }
54
55 // Check if the knot knows about any Dids;
56 // if it does, it is already initialized and we can repopulate the
57 // Jetstream subscriptions.
58 dids, err := db.GetAllDids()
59 if err != nil {
60 return nil, fmt.Errorf("failed to get all Dids: %w", err)
61 }
62 if len(dids) > 0 {
63 h.knotInitialized = true
64 close(h.init)
65 h.jc.UpdateDids(dids)
66 }
67
68 r.Get("/", h.Index)
69 r.Route("/{did}", func(r chi.Router) {
70 // Repo routes
71 r.Route("/{name}", func(r chi.Router) {
72 r.Post("/collaborator/add", h.AddRepoCollaborator)
73
74 r.Get("/", h.RepoIndex)
75 r.Get("/info/refs", h.InfoRefs)
76 r.Post("/git-upload-pack", h.UploadPack)
77
78 r.Route("/tree/{ref}", func(r chi.Router) {
79 r.Get("/", h.RepoIndex)
80 r.Get("/*", h.RepoTree)
81 })
82
83 r.Route("/blob/{ref}", func(r chi.Router) {
84 r.Get("/*", h.Blob)
85 })
86
87 r.Get("/log/{ref}", h.Log)
88 r.Get("/archive/{file}", h.Archive)
89 r.Get("/commit/{ref}", h.Diff)
90 r.Get("/tags", h.Tags)
91 r.Get("/branches", h.Branches)
92 })
93 })
94
95 // Create a new repository.
96 r.Route("/repo", func(r chi.Router) {
97 r.Use(h.VerifySignature)
98 r.Put("/new", h.NewRepo)
99 })
100
101 r.Route("/member", func(r chi.Router) {
102 r.Use(h.VerifySignature)
103 r.Put("/add", h.AddMember)
104 })
105
106 // Initialize the knot with an owner and public key.
107 r.With(h.VerifySignature).Post("/init", h.Init)
108
109 // Health check. Used for two-way verification with appview.
110 r.With(h.VerifySignature).Get("/health", h.Health)
111
112 // All public keys on the knot.
113 r.Get("/keys", h.Keys)
114
115 return r, nil
116}