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 r.Delete("/", h.RemoveRepo)
100 })
101
102 r.Route("/member", func(r chi.Router) {
103 r.Use(h.VerifySignature)
104 r.Put("/add", h.AddMember)
105 })
106
107 // Initialize the knot with an owner and public key.
108 r.With(h.VerifySignature).Post("/init", h.Init)
109
110 // Health check. Used for two-way verification with appview.
111 r.With(h.VerifySignature).Get("/health", h.Health)
112
113 // All public keys on the knot.
114 r.Get("/keys", h.Keys)
115
116 return r, nil
117}