this repo has no description
1package knotserver
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "log"
8 "net/http"
9
10 "github.com/go-chi/chi/v5"
11 tangled "github.com/icyphox/bild/api/tangled"
12 "github.com/icyphox/bild/knotserver/config"
13 "github.com/icyphox/bild/knotserver/db"
14 "github.com/icyphox/bild/knotserver/jsclient"
15)
16
17type Handle struct {
18 c *config.Config
19 db *db.DB
20 js *jsclient.JetstreamClient
21}
22
23func Setup(ctx context.Context, c *config.Config, db *db.DB) (http.Handler, error) {
24 r := chi.NewRouter()
25
26 h := Handle{
27 c: c,
28 db: db,
29 }
30
31 err := h.StartJetstream(ctx)
32 if err != nil {
33 return nil, fmt.Errorf("failed to start jetstream: %w", err)
34 }
35
36 r.Get("/", h.Index)
37 r.Route("/{did}", func(r chi.Router) {
38 // Repo routes
39 r.Route("/{name}", func(r chi.Router) {
40 r.Get("/", h.RepoIndex)
41 r.Get("/info/refs", h.InfoRefs)
42 r.Post("/git-upload-pack", h.UploadPack)
43
44 r.Route("/tree/{ref}", func(r chi.Router) {
45 r.Get("/*", h.RepoTree)
46 })
47
48 r.Route("/blob/{ref}", func(r chi.Router) {
49 r.Get("/*", h.FileContent)
50 })
51
52 r.Get("/log/{ref}", h.Log)
53 r.Get("/archive/{file}", h.Archive)
54 r.Get("/commit/{ref}", h.Diff)
55 r.Get("/refs/", h.Refs)
56 })
57 })
58
59 // Create a new repository
60 r.Route("/repo", func(r chi.Router) {
61 r.Use(h.VerifySignature)
62 r.Put("/new", h.NewRepo)
63 })
64
65 // Add a new user to the knot
66 // r.With(h.VerifySignature).Put("/user", h.AddUser)
67
68 // Health check. Used for two-way verification with appview.
69 r.With(h.VerifySignature).Get("/health", h.Health)
70
71 // All public keys on the knot
72 r.Get("/keys", h.Keys)
73
74 return r, nil
75}
76
77func (h *Handle) StartJetstream(ctx context.Context) error {
78 colections := []string{tangled.PublicKeyNSID}
79 dids := []string{}
80
81 h.js = jsclient.NewJetstreamClient(colections, dids)
82 messages, err := h.js.ReadJetstream(ctx)
83 if err != nil {
84 return fmt.Errorf("failed to read from jetstream: %w", err)
85 }
86
87 go func() {
88 for msg := range messages {
89 var data map[string]interface{}
90 if err := json.Unmarshal(msg, &data); err != nil {
91 log.Printf("error unmarshaling message: %v", err)
92 continue
93 }
94
95 if kind, ok := data["kind"].(string); ok && kind == "commit" {
96 commit := data["commit"].(map[string]interface{})
97
98 switch commit["collection"].(string) {
99 case tangled.PublicKeyNSID:
100 record := commit["record"].(map[string]interface{})
101 if err := h.db.AddPublicKeyFromRecord(record); err != nil {
102 log.Printf("failed to add public key: %v", err)
103 }
104 log.Printf("added public key from firehose: %s", data["did"])
105 default:
106 }
107 }
108
109 }
110 }()
111
112 return nil
113}