forked from tangled.org/core
this repo has no description

knotserver: use slog everywhere

Changed files
+185 -76
cmd
knotserver
knotserver
log
+15 -12
cmd/knotserver/main.go
··· 3 import ( 4 "context" 5 "fmt" 6 - "log" 7 - "log/slog" 8 "net/http" 9 - "os" 10 11 "github.com/sotangled/tangled/knotserver" 12 "github.com/sotangled/tangled/knotserver/config" 13 "github.com/sotangled/tangled/knotserver/db" 14 "github.com/sotangled/tangled/rbac" 15 ) 16 ··· 19 // ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) 20 // defer stop() 21 22 - slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, nil))) 23 24 c, err := config.Load(ctx) 25 if err != nil { 26 - log.Fatal(err) 27 } 28 29 if c.Server.Dev { 30 - log.Println("running in dev mode, signature verification is disabled") 31 } 32 33 db, err := db.Setup(c.Server.DBPath) 34 if err != nil { 35 - log.Fatalf("failed to setup db: %s", err) 36 } 37 38 e, err := rbac.NewEnforcer(c.Server.DBPath) 39 if err != nil { 40 - log.Fatalf("failed to setup rbac enforcer: %s", err) 41 } 42 43 - mux, err := knotserver.Setup(ctx, c, db, e) 44 if err != nil { 45 - log.Fatal(err) 46 } 47 48 addr := fmt.Sprintf("%s:%d", c.Server.Host, c.Server.Port) 49 50 - log.Println("starting main server on", addr) 51 - log.Fatal(http.ListenAndServe(addr, mux)) 52 }
··· 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 8 "github.com/sotangled/tangled/knotserver" 9 "github.com/sotangled/tangled/knotserver/config" 10 "github.com/sotangled/tangled/knotserver/db" 11 + "github.com/sotangled/tangled/log" 12 "github.com/sotangled/tangled/rbac" 13 ) 14 ··· 17 // ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) 18 // defer stop() 19 20 + l := log.New("knotserver") 21 22 c, err := config.Load(ctx) 23 if err != nil { 24 + l.Error("failed to load config", "error", err) 25 + return 26 } 27 28 if c.Server.Dev { 29 + l.Info("running in dev mode, signature verification is disabled") 30 } 31 32 db, err := db.Setup(c.Server.DBPath) 33 if err != nil { 34 + l.Error("failed to setup db", "error", err) 35 + return 36 } 37 38 e, err := rbac.NewEnforcer(c.Server.DBPath) 39 if err != nil { 40 + l.Error("failed to setup rbac enforcer", "error", err) 41 + return 42 } 43 44 + mux, err := knotserver.Setup(ctx, c, db, e, l) 45 if err != nil { 46 + l.Error("failed to setup server", "error", err) 47 + return 48 } 49 50 addr := fmt.Sprintf("%s:%d", c.Server.Host, c.Server.Port) 51 52 + l.Info("starting main server", "address", addr) 53 + l.Error("server error", "error", http.ListenAndServe(addr, mux)) 54 + return 55 }
+3 -3
knotserver/file.go
··· 3 import ( 4 "bytes" 5 "io" 6 - "log" 7 "net/http" 8 "strings" 9 ··· 43 } 44 } 45 46 - func (h *Handle) showFile(content string, data map[string]any, w http.ResponseWriter) { 47 lc, err := countLines(strings.NewReader(content)) 48 if err != nil { 49 // Non-fatal, we'll just skip showing line numbers in the template. 50 - log.Printf("counting lines: %s", err) 51 } 52 53 lines := make([]int, lc)
··· 3 import ( 4 "bytes" 5 "io" 6 + "log/slog" 7 "net/http" 8 "strings" 9 ··· 43 } 44 } 45 46 + func (h *Handle) showFile(content string, data map[string]any, w http.ResponseWriter, l *slog.Logger) { 47 lc, err := countLines(strings.NewReader(content)) 48 if err != nil { 49 // Non-fatal, we'll just skip showing line numbers in the template. 50 + l.Warn("counting lines", "error", err) 51 } 52 53 lines := make([]int, lc)
+3 -4
knotserver/git.go
··· 3 import ( 4 "compress/gzip" 5 "io" 6 - "log" 7 "net/http" 8 "path/filepath" 9 ··· 26 27 if err := cmd.InfoRefs(); err != nil { 28 http.Error(w, err.Error(), 500) 29 - log.Printf("git: failed to execute git-upload-pack (info/refs) %s", err) 30 return 31 } 32 } ··· 53 reader, err := gzip.NewReader(r.Body) 54 if err != nil { 55 http.Error(w, err.Error(), 500) 56 - log.Printf("git: failed to create gzip reader: %s", err) 57 return 58 } 59 defer reader.Close() ··· 62 cmd.Stdin = reader 63 if err := cmd.UploadPack(); err != nil { 64 http.Error(w, err.Error(), 500) 65 - log.Printf("git: failed to execute git-upload-pack %s", err) 66 return 67 } 68 }
··· 3 import ( 4 "compress/gzip" 5 "io" 6 "net/http" 7 "path/filepath" 8 ··· 25 26 if err := cmd.InfoRefs(); err != nil { 27 http.Error(w, err.Error(), 500) 28 + d.l.Error("git: failed to execute git-upload-pack (info/refs)", "handler", "InfoRefs", "error", err) 29 return 30 } 31 } ··· 52 reader, err := gzip.NewReader(r.Body) 53 if err != nil { 54 http.Error(w, err.Error(), 500) 55 + d.l.Error("git: failed to create gzip reader", "handler", "UploadPack", "error", err) 56 return 57 } 58 defer reader.Close() ··· 61 cmd.Stdin = reader 62 if err := cmd.UploadPack(); err != nil { 63 http.Error(w, err.Error(), 500) 64 + d.l.Error("git: failed to execute git-upload-pack", "handler", "UploadPack", "error", err) 65 return 66 } 67 }
+4 -1
knotserver/handler.go
··· 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 8 "github.com/go-chi/chi/v5" ··· 21 db *db.DB 22 js *jsclient.JetstreamClient 23 e *rbac.Enforcer 24 25 // init is a channel that is closed when the knot has been initailized 26 // i.e. when the first user (knot owner) has been added. ··· 28 knotInitialized bool 29 } 30 31 - func Setup(ctx context.Context, c *config.Config, db *db.DB, e *rbac.Enforcer) (http.Handler, error) { 32 r := chi.NewRouter() 33 34 h := Handle{ 35 c: c, 36 db: db, 37 e: e, 38 init: make(chan struct{}), 39 } 40
··· 3 import ( 4 "context" 5 "fmt" 6 + "log/slog" 7 "net/http" 8 9 "github.com/go-chi/chi/v5" ··· 22 db *db.DB 23 js *jsclient.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. ··· 30 knotInitialized bool 31 } 32 33 + func Setup(ctx context.Context, c *config.Config, db *db.DB, e *rbac.Enforcer, 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 init: make(chan struct{}), 42 } 43
+66 -34
knotserver/jetstream.go
··· 5 "encoding/json" 6 "fmt" 7 "io" 8 - "log" 9 "net/http" 10 "net/url" 11 "strings" ··· 14 "github.com/sotangled/tangled/api/tangled" 15 "github.com/sotangled/tangled/knotserver/db" 16 "github.com/sotangled/tangled/knotserver/jsclient" 17 ) 18 19 func (h *Handle) StartJetstream(ctx context.Context) error { 20 collections := []string{tangled.PublicKeyNSID, tangled.KnotMemberNSID} 21 dids := []string{} 22 23 - lastTimeUs, err := h.getLastTimeUs() 24 if err != nil { 25 return err 26 } ··· 31 return fmt.Errorf("failed to read from jetstream: %w", err) 32 } 33 34 - go h.processMessages(messages) 35 36 return nil 37 } 38 39 - func (h *Handle) getLastTimeUs() (int64, error) { 40 lastTimeUs, err := h.db.GetLastTimeUs() 41 if err != nil { 42 - log.Println("couldn't get last time us, starting from now") 43 lastTimeUs = time.Now().UnixMicro() 44 } 45 46 // If last time is older than a week, start from now 47 if time.Now().UnixMicro()-lastTimeUs > 7*24*60*60*1000*1000 { 48 lastTimeUs = time.Now().UnixMicro() 49 - log.Printf("last time us is older than a week. discarding that and starting from now.") 50 err = h.db.SaveLastTimeUs(lastTimeUs) 51 if err != nil { 52 - log.Println("failed to save last time us") 53 } 54 } 55 56 - log.Printf("found last time_us %d", lastTimeUs) 57 return lastTimeUs, nil 58 } 59 60 - func (h *Handle) processPublicKey(did string, record map[string]interface{}) { 61 if err := h.db.AddPublicKeyFromRecord(did, record); err != nil { 62 - log.Printf("failed to add public key: %v", err) 63 - } else { 64 - log.Printf("added public key from firehose: %s", did) 65 } 66 } 67 68 - func (h *Handle) fetchAndAddKeys(did string) { 69 keysEndpoint, err := url.JoinPath(h.c.AppViewEndpoint, "keys", did) 70 if err != nil { 71 - log.Printf("error building endpoint url: %s: %v", did, err) 72 - return 73 } 74 75 resp, err := http.Get(keysEndpoint) 76 if err != nil { 77 - log.Printf("error getting keys for %s: %v", did, err) 78 - return 79 } 80 defer resp.Body.Close() 81 82 plaintext, err := io.ReadAll(resp.Body) 83 if err != nil { 84 - log.Printf("error reading response body: %v", err) 85 - return 86 } 87 88 for _, key := range strings.Split(string(plaintext), "\n") { ··· 94 } 95 pk.Key = key 96 if err := h.db.AddPublicKey(pk); err != nil { 97 - log.Printf("failed to add public key: %v", err) 98 } 99 } 100 } 101 102 - func (h *Handle) processKnotMember(did string, record map[string]interface{}) { 103 ok, err := h.e.E.Enforce(did, ThisServer, ThisServer, "server:invite") 104 if err != nil || !ok { 105 - log.Printf("failed to add member from did %s", did) 106 - return 107 } 108 109 - log.Printf("adding member") 110 if err := h.e.AddMember(ThisServer, record["member"].(string)); err != nil { 111 - log.Printf("failed to add member: %v", err) 112 - } else { 113 - log.Printf("added member from firehose: %s", record["member"]) 114 } 115 116 - h.fetchAndAddKeys(did) 117 h.js.UpdateDids([]string{did}) 118 } 119 120 - func (h *Handle) processMessages(messages <-chan []byte) { 121 <-h.init 122 - log.Println("initalized jetstream watcher") 123 124 for msg := range messages { 125 var data map[string]interface{} 126 if err := json.Unmarshal(msg, &data); err != nil { 127 - log.Printf("error unmarshaling message: %v", err) 128 continue 129 } 130 ··· 133 did := data["did"].(string) 134 record := commit["record"].(map[string]interface{}) 135 136 switch commit["collection"].(string) { 137 case tangled.PublicKeyNSID: 138 - h.processPublicKey(did, record) 139 case tangled.KnotMemberNSID: 140 - h.processKnotMember(did, record) 141 } 142 143 lastTimeUs := int64(data["time_us"].(float64)) 144 if err := h.db.SaveLastTimeUs(lastTimeUs); err != nil { 145 - log.Printf("failed to save last time us: %v", err) 146 } 147 } 148 }
··· 5 "encoding/json" 6 "fmt" 7 "io" 8 "net/http" 9 "net/url" 10 "strings" ··· 13 "github.com/sotangled/tangled/api/tangled" 14 "github.com/sotangled/tangled/knotserver/db" 15 "github.com/sotangled/tangled/knotserver/jsclient" 16 + "github.com/sotangled/tangled/log" 17 ) 18 19 func (h *Handle) StartJetstream(ctx context.Context) error { 20 + l := h.l.With("component", "jetstream") 21 + ctx = log.IntoContext(ctx, l) 22 collections := []string{tangled.PublicKeyNSID, tangled.KnotMemberNSID} 23 dids := []string{} 24 25 + lastTimeUs, err := h.getLastTimeUs(ctx) 26 if err != nil { 27 return err 28 } ··· 33 return fmt.Errorf("failed to read from jetstream: %w", err) 34 } 35 36 + go h.processMessages(ctx, messages) 37 38 return nil 39 } 40 41 + func (h *Handle) getLastTimeUs(ctx context.Context) (int64, error) { 42 + l := log.FromContext(ctx) 43 lastTimeUs, err := h.db.GetLastTimeUs() 44 if err != nil { 45 + l.Info("couldn't get last time us, starting from now") 46 lastTimeUs = time.Now().UnixMicro() 47 } 48 49 // If last time is older than a week, start from now 50 if time.Now().UnixMicro()-lastTimeUs > 7*24*60*60*1000*1000 { 51 lastTimeUs = time.Now().UnixMicro() 52 + l.Info("last time us is older than a week. discarding that and starting from now") 53 err = h.db.SaveLastTimeUs(lastTimeUs) 54 if err != nil { 55 + l.Error("failed to save last time us") 56 } 57 } 58 59 + l.Info("found last time_us", "time_us", lastTimeUs) 60 return lastTimeUs, nil 61 } 62 63 + func (h *Handle) processPublicKey(ctx context.Context, did string, record map[string]interface{}) error { 64 + l := log.FromContext(ctx) 65 if err := h.db.AddPublicKeyFromRecord(did, record); err != nil { 66 + l.Error("failed to add public key", "error", err) 67 + return fmt.Errorf("failed to add public key: %w", err) 68 } 69 + l.Info("added public key from firehose", "did", did) 70 + return nil 71 } 72 73 + func (h *Handle) fetchAndAddKeys(ctx context.Context, did string) error { 74 + l := log.FromContext(ctx) 75 + 76 keysEndpoint, err := url.JoinPath(h.c.AppViewEndpoint, "keys", did) 77 if err != nil { 78 + l.Error("error building endpoint url", "did", did, "error", err.Error()) 79 + return fmt.Errorf("error building endpoint url: %w", err) 80 } 81 82 resp, err := http.Get(keysEndpoint) 83 if err != nil { 84 + l.Error("error getting keys", "did", did, "error", err) 85 + return fmt.Errorf("error getting keys: %w", err) 86 } 87 defer resp.Body.Close() 88 89 plaintext, err := io.ReadAll(resp.Body) 90 if err != nil { 91 + l.Error("error reading response body", "error", err) 92 + return fmt.Errorf("error reading response body: %w", err) 93 } 94 95 for _, key := range strings.Split(string(plaintext), "\n") { ··· 101 } 102 pk.Key = key 103 if err := h.db.AddPublicKey(pk); err != nil { 104 + l.Error("failed to add public key", "error", err) 105 + return fmt.Errorf("failed to add public key: %w", err) 106 } 107 } 108 + return nil 109 } 110 111 + func (h *Handle) processKnotMember(ctx context.Context, did string, record map[string]interface{}) error { 112 + l := log.FromContext(ctx) 113 ok, err := h.e.E.Enforce(did, ThisServer, ThisServer, "server:invite") 114 if err != nil || !ok { 115 + l.Error("failed to add member", "did", did) 116 + return fmt.Errorf("failed to enforce permissions: %w", err) 117 } 118 119 + l.Info("adding member") 120 if err := h.e.AddMember(ThisServer, record["member"].(string)); err != nil { 121 + l.Error("failed to add member", "error", err) 122 + return fmt.Errorf("failed to add member: %w", err) 123 + } 124 + l.Info("added member from firehose", "member", record["member"]) 125 + 126 + if err := h.db.AddDid(did); err != nil { 127 + l.Error("failed to add did", "error", err) 128 + return fmt.Errorf("failed to add did: %w", err) 129 } 130 131 + if err := h.fetchAndAddKeys(ctx, did); err != nil { 132 + return fmt.Errorf("failed to fetch and add keys: %w", err) 133 + } 134 + 135 h.js.UpdateDids([]string{did}) 136 + return nil 137 } 138 139 + func (h *Handle) processMessages(ctx context.Context, messages <-chan []byte) { 140 + l := log.FromContext(ctx) 141 + l.Info("waiting for knot to be initialized") 142 <-h.init 143 + l.Info("initialized jetstream watcher") 144 145 for msg := range messages { 146 var data map[string]interface{} 147 if err := json.Unmarshal(msg, &data); err != nil { 148 + l.Error("error unmarshaling message", "error", err) 149 continue 150 } 151 ··· 154 did := data["did"].(string) 155 record := commit["record"].(map[string]interface{}) 156 157 + var processErr error 158 switch commit["collection"].(string) { 159 case tangled.PublicKeyNSID: 160 + if err := h.processPublicKey(ctx, did, record); err != nil { 161 + processErr = fmt.Errorf("failed to process public key: %w", err) 162 + } 163 case tangled.KnotMemberNSID: 164 + if err := h.processKnotMember(ctx, did, record); err != nil { 165 + processErr = fmt.Errorf("failed to process knot member: %w", err) 166 + } 167 + } 168 + 169 + if processErr != nil { 170 + l.Error("error processing message", "error", processErr) 171 + continue 172 } 173 174 lastTimeUs := int64(data["time_us"].(float64)) 175 if err := h.db.SaveLastTimeUs(lastTimeUs); err != nil { 176 + l.Error("failed to save last time us", "error", err) 177 + continue 178 } 179 } 180 }
+45 -22
knotserver/routes.go
··· 9 "errors" 10 "fmt" 11 "html/template" 12 - "log" 13 "net/http" 14 "path/filepath" 15 "strconv" ··· 30 31 func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) { 32 path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 33 34 gr, err := git.Open(path, "") 35 if err != nil { ··· 37 writeMsg(w, "repo empty") 38 return 39 } else { 40 - log.Println(err) 41 notFound(w) 42 return 43 } ··· 45 commits, err := gr.Commits() 46 if err != nil { 47 writeError(w, err.Error(), http.StatusInternalServerError) 48 - log.Println(err) 49 return 50 } 51 ··· 73 } 74 75 if readmeContent == "" { 76 - log.Printf("no readme found for %s", path) 77 } 78 79 mainBranch, err := gr.FindMainBranch(h.c.Repo.MainBranch) 80 if err != nil { 81 writeError(w, err.Error(), http.StatusInternalServerError) 82 - log.Println(err) 83 return 84 } 85 ··· 100 treePath := chi.URLParam(r, "*") 101 ref := chi.URLParam(r, "ref") 102 103 path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 104 gr, err := git.Open(path, ref) 105 if err != nil { ··· 110 files, err := gr.FileTree(treePath) 111 if err != nil { 112 writeError(w, err.Error(), http.StatusInternalServerError) 113 - log.Println(err) 114 return 115 } 116 ··· 133 treePath := chi.URLParam(r, "*") 134 ref := chi.URLParam(r, "ref") 135 136 path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 137 gr, err := git.Open(path, ref) 138 if err != nil { ··· 155 if raw { 156 h.showRaw(string(safe), w) 157 } else { 158 - h.showFile(string(safe), data, w) 159 } 160 } 161 162 func (h *Handle) Archive(w http.ResponseWriter, r *http.Request) { 163 name := chi.URLParam(r, "name") 164 file := chi.URLParam(r, "file") 165 166 // TODO: extend this to add more files compression (e.g.: xz) 167 if !strings.HasSuffix(file, ".tar.gz") { ··· 192 if err != nil { 193 // once we start writing to the body we can't report error anymore 194 // so we are only left with printing the error. 195 - log.Println(err) 196 return 197 } 198 ··· 200 if err != nil { 201 // once we start writing to the body we can't report error anymore 202 // so we are only left with printing the error. 203 - log.Println(err) 204 return 205 } 206 } 207 208 func (h *Handle) Log(w http.ResponseWriter, r *http.Request) { 209 - fmt.Println(r.URL.Path) 210 ref := chi.URLParam(r, "ref") 211 212 - path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 213 gr, err := git.Open(path, ref) 214 if err != nil { 215 notFound(w) ··· 219 commits, err := gr.Commits() 220 if err != nil { 221 writeError(w, err.Error(), http.StatusInternalServerError) 222 - log.Println(err) 223 return 224 } 225 ··· 269 func (h *Handle) Diff(w http.ResponseWriter, r *http.Request) { 270 ref := chi.URLParam(r, "ref") 271 272 path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 273 gr, err := git.Open(path, ref) 274 if err != nil { ··· 279 diff, err := gr.Diff() 280 if err != nil { 281 writeError(w, err.Error(), http.StatusInternalServerError) 282 - log.Println(err) 283 return 284 } 285 ··· 297 298 func (h *Handle) Refs(w http.ResponseWriter, r *http.Request) { 299 path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 300 gr, err := git.Open(path, "") 301 if err != nil { 302 notFound(w) ··· 306 tags, err := gr.Tags() 307 if err != nil { 308 // Non-fatal, we *should* have at least one branch to show. 309 - log.Println(err) 310 } 311 312 branches, err := gr.Branches() 313 if err != nil { 314 - log.Println(err) 315 writeError(w, err.Error(), http.StatusInternalServerError) 316 return 317 } ··· 327 } 328 329 func (h *Handle) Keys(w http.ResponseWriter, r *http.Request) { 330 switch r.Method { 331 case http.MethodGet: 332 keys, err := h.db.GetAllPublicKeys() 333 if err != nil { 334 writeError(w, err.Error(), http.StatusInternalServerError) 335 - log.Println(err) 336 return 337 } 338 ··· 358 359 if err := h.db.AddPublicKey(pk); err != nil { 360 writeError(w, err.Error(), http.StatusInternalServerError) 361 - log.Printf("adding public key: %s", err) 362 return 363 } 364 ··· 368 } 369 370 func (h *Handle) NewRepo(w http.ResponseWriter, r *http.Request) { 371 data := struct { 372 Did string `json:"did"` 373 Name string `json:"name"` ··· 385 repoPath := filepath.Join(h.c.Repo.ScanPath, relativeRepoPath) 386 err := git.InitBare(repoPath) 387 if err != nil { 388 - log.Println(err) 389 writeError(w, err.Error(), http.StatusInternalServerError) 390 return 391 } ··· 393 // add perms for this user to access the repo 394 err = h.e.AddRepo(did, ThisServer, relativeRepoPath) 395 if err != nil { 396 - log.Println(err) 397 writeError(w, err.Error(), http.StatusInternalServerError) 398 return 399 } ··· 402 } 403 404 func (h *Handle) AddMember(w http.ResponseWriter, r *http.Request) { 405 data := struct { 406 Did string `json:"did"` 407 PublicKeys []string `json:"keys"` ··· 427 428 h.js.UpdateDids([]string{did}) 429 if err := h.e.AddMember(ThisServer, did); err != nil { 430 - log.Println(err) 431 writeError(w, err.Error(), http.StatusInternalServerError) 432 return 433 } ··· 436 } 437 438 func (h *Handle) Init(w http.ResponseWriter, r *http.Request) { 439 if h.knotInitialized { 440 writeError(w, "knot already initialized", http.StatusConflict) 441 return ··· 447 }{} 448 449 if err := json.NewDecoder(r.Body).Decode(&data); err != nil { 450 writeError(w, "invalid request body", http.StatusBadRequest) 451 return 452 } 453 454 if data.Did == "" { 455 writeError(w, "did is empty", http.StatusBadRequest) 456 return 457 } ··· 464 pk.Key = k 465 err := h.db.AddPublicKey(pk) 466 if err != nil { 467 writeError(w, err.Error(), http.StatusInternalServerError) 468 return 469 } 470 } 471 } else { 472 writeError(w, err.Error(), http.StatusInternalServerError) 473 return 474 } 475 476 h.js.UpdateDids([]string{data.Did}) 477 if err := h.e.AddOwner(ThisServer, data.Did); err != nil { 478 - log.Println(err) 479 writeError(w, err.Error(), http.StatusInternalServerError) 480 return 481 } 482 - // Signal that the knot is ready 483 close(h.init) 484 485 mac := hmac.New(sha256.New, []byte(h.c.Server.Secret))
··· 9 "errors" 10 "fmt" 11 "html/template" 12 "net/http" 13 "path/filepath" 14 "strconv" ··· 29 30 func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) { 31 path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 32 + l := h.l.With("path", path, "handler", "RepoIndex") 33 34 gr, err := git.Open(path, "") 35 if err != nil { ··· 37 writeMsg(w, "repo empty") 38 return 39 } else { 40 + l.Error("opening repo", "error", err.Error()) 41 notFound(w) 42 return 43 } ··· 45 commits, err := gr.Commits() 46 if err != nil { 47 writeError(w, err.Error(), http.StatusInternalServerError) 48 + l.Error("fetching commits", "error", err.Error()) 49 return 50 } 51 ··· 73 } 74 75 if readmeContent == "" { 76 + l.Warn("no readme found") 77 } 78 79 mainBranch, err := gr.FindMainBranch(h.c.Repo.MainBranch) 80 if err != nil { 81 writeError(w, err.Error(), http.StatusInternalServerError) 82 + l.Error("finding main branch", "error", err.Error()) 83 return 84 } 85 ··· 100 treePath := chi.URLParam(r, "*") 101 ref := chi.URLParam(r, "ref") 102 103 + l := h.l.With("handler", "RepoTree", "ref", ref, "treePath", treePath) 104 + 105 path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 106 gr, err := git.Open(path, ref) 107 if err != nil { ··· 112 files, err := gr.FileTree(treePath) 113 if err != nil { 114 writeError(w, err.Error(), http.StatusInternalServerError) 115 + l.Error("file tree", "error", err.Error()) 116 return 117 } 118 ··· 135 treePath := chi.URLParam(r, "*") 136 ref := chi.URLParam(r, "ref") 137 138 + l := h.l.With("handler", "FileContent", "ref", ref, "treePath", treePath) 139 + 140 path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 141 gr, err := git.Open(path, ref) 142 if err != nil { ··· 159 if raw { 160 h.showRaw(string(safe), w) 161 } else { 162 + h.showFile(string(safe), data, w, l) 163 } 164 } 165 166 func (h *Handle) Archive(w http.ResponseWriter, r *http.Request) { 167 name := chi.URLParam(r, "name") 168 file := chi.URLParam(r, "file") 169 + 170 + l := h.l.With("handler", "Archive", "name", name, "file", file) 171 172 // TODO: extend this to add more files compression (e.g.: xz) 173 if !strings.HasSuffix(file, ".tar.gz") { ··· 198 if err != nil { 199 // once we start writing to the body we can't report error anymore 200 // so we are only left with printing the error. 201 + l.Error("writing tar file", "error", err.Error()) 202 return 203 } 204 ··· 206 if err != nil { 207 // once we start writing to the body we can't report error anymore 208 // so we are only left with printing the error. 209 + l.Error("flushing?", "error", err.Error()) 210 return 211 } 212 } 213 214 func (h *Handle) Log(w http.ResponseWriter, r *http.Request) { 215 ref := chi.URLParam(r, "ref") 216 + path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 217 218 + l := h.l.With("handler", "Log", "ref", ref, "path", path) 219 + 220 gr, err := git.Open(path, ref) 221 if err != nil { 222 notFound(w) ··· 226 commits, err := gr.Commits() 227 if err != nil { 228 writeError(w, err.Error(), http.StatusInternalServerError) 229 + l.Error("fetching commits", "error", err.Error()) 230 return 231 } 232 ··· 276 func (h *Handle) Diff(w http.ResponseWriter, r *http.Request) { 277 ref := chi.URLParam(r, "ref") 278 279 + l := h.l.With("handler", "Diff", "ref", ref) 280 + 281 path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 282 gr, err := git.Open(path, ref) 283 if err != nil { ··· 288 diff, err := gr.Diff() 289 if err != nil { 290 writeError(w, err.Error(), http.StatusInternalServerError) 291 + l.Error("getting diff", "error", err.Error()) 292 return 293 } 294 ··· 306 307 func (h *Handle) Refs(w http.ResponseWriter, r *http.Request) { 308 path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 309 + l := h.l.With("handler", "Refs") 310 + 311 gr, err := git.Open(path, "") 312 if err != nil { 313 notFound(w) ··· 317 tags, err := gr.Tags() 318 if err != nil { 319 // Non-fatal, we *should* have at least one branch to show. 320 + l.Error("getting tags", "error", err.Error()) 321 } 322 323 branches, err := gr.Branches() 324 if err != nil { 325 + l.Error("getting branches", "error", err.Error()) 326 writeError(w, err.Error(), http.StatusInternalServerError) 327 return 328 } ··· 338 } 339 340 func (h *Handle) Keys(w http.ResponseWriter, r *http.Request) { 341 + l := h.l.With("handler", "Keys") 342 + 343 switch r.Method { 344 case http.MethodGet: 345 keys, err := h.db.GetAllPublicKeys() 346 if err != nil { 347 writeError(w, err.Error(), http.StatusInternalServerError) 348 + l.Error("getting public keys", "error", err.Error()) 349 return 350 } 351 ··· 371 372 if err := h.db.AddPublicKey(pk); err != nil { 373 writeError(w, err.Error(), http.StatusInternalServerError) 374 + l.Error("adding public key", "error", err.Error()) 375 return 376 } 377 ··· 381 } 382 383 func (h *Handle) NewRepo(w http.ResponseWriter, r *http.Request) { 384 + l := h.l.With("handler", "NewRepo") 385 + 386 data := struct { 387 Did string `json:"did"` 388 Name string `json:"name"` ··· 400 repoPath := filepath.Join(h.c.Repo.ScanPath, relativeRepoPath) 401 err := git.InitBare(repoPath) 402 if err != nil { 403 + l.Error("initializing bare repo", "error", err.Error()) 404 writeError(w, err.Error(), http.StatusInternalServerError) 405 return 406 } ··· 408 // add perms for this user to access the repo 409 err = h.e.AddRepo(did, ThisServer, relativeRepoPath) 410 if err != nil { 411 + l.Error("adding repo permissions", "error", err.Error()) 412 writeError(w, err.Error(), http.StatusInternalServerError) 413 return 414 } ··· 417 } 418 419 func (h *Handle) AddMember(w http.ResponseWriter, r *http.Request) { 420 + l := h.l.With("handler", "AddMember") 421 + 422 data := struct { 423 Did string `json:"did"` 424 PublicKeys []string `json:"keys"` ··· 444 445 h.js.UpdateDids([]string{did}) 446 if err := h.e.AddMember(ThisServer, did); err != nil { 447 + l.Error("adding member", "error", err.Error()) 448 writeError(w, err.Error(), http.StatusInternalServerError) 449 return 450 } ··· 453 } 454 455 func (h *Handle) Init(w http.ResponseWriter, r *http.Request) { 456 + l := h.l.With("handler", "Init") 457 + 458 if h.knotInitialized { 459 writeError(w, "knot already initialized", http.StatusConflict) 460 return ··· 466 }{} 467 468 if err := json.NewDecoder(r.Body).Decode(&data); err != nil { 469 + l.Error("failed to decode request body", "error", err.Error()) 470 writeError(w, "invalid request body", http.StatusBadRequest) 471 return 472 } 473 474 if data.Did == "" { 475 + l.Error("empty DID in request") 476 writeError(w, "did is empty", http.StatusBadRequest) 477 return 478 } ··· 485 pk.Key = k 486 err := h.db.AddPublicKey(pk) 487 if err != nil { 488 + l.Error("failed to add public key", "error", err.Error()) 489 writeError(w, err.Error(), http.StatusInternalServerError) 490 return 491 } 492 } 493 } else { 494 + l.Error("failed to add DID", "error", err.Error()) 495 writeError(w, err.Error(), http.StatusInternalServerError) 496 return 497 } 498 499 h.js.UpdateDids([]string{data.Did}) 500 if err := h.e.AddOwner(ThisServer, data.Did); err != nil { 501 + l.Error("adding owner", "error", err.Error()) 502 writeError(w, err.Error(), http.StatusInternalServerError) 503 return 504 } 505 + 506 close(h.init) 507 508 mac := hmac.New(sha256.New, []byte(h.c.Server.Secret))
+49
log/log.go
···
··· 1 + package log 2 + 3 + import ( 4 + "context" 5 + "log/slog" 6 + "os" 7 + ) 8 + 9 + // NewHandler sets up a new slog.Handler with the service name 10 + // as an attribute 11 + func NewHandler(name string) slog.Handler { 12 + handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{}) 13 + 14 + var attrs []slog.Attr 15 + attrs = append(attrs, slog.Attr{Key: "service", Value: slog.StringValue(name)}) 16 + handler.WithAttrs(attrs) 17 + return handler 18 + } 19 + 20 + func New(name string) *slog.Logger { 21 + return slog.New(NewHandler(name)) 22 + } 23 + 24 + func NewContext(ctx context.Context, name string) context.Context { 25 + return IntoContext(ctx, New(name)) 26 + } 27 + 28 + type ctxKey struct{} 29 + 30 + // IntoContext adds a logger to a context. Use FromContext to 31 + // pull the logger out. 32 + func IntoContext(ctx context.Context, l *slog.Logger) context.Context { 33 + return context.WithValue(ctx, ctxKey{}, l) 34 + } 35 + 36 + // FromContext returns a logger from a context.Context; 37 + // if the passed context is nil, we return the default slog 38 + // logger. 39 + func FromContext(ctx context.Context) *slog.Logger { 40 + if ctx != nil { 41 + v := ctx.Value(ctxKey{}) 42 + if v == nil { 43 + return slog.Default() 44 + } 45 + return v.(*slog.Logger) 46 + } 47 + 48 + return slog.Default() 49 + }