package main import ( "context" "log" "strings" "fn-registry/functions/infra" ) func (s *Server) watchLoop(ctx context.Context, root, kind string) { ch, err := infra.WatchDirFsnotify(ctx, root) if err != nil { log.Printf("watcher %s: %v", root, err) return } for ev := range ch { if !strings.HasSuffix(ev.Path, ".md") { continue } s.handleFsEvent(kind, ev) } } func (s *Server) handleFsEvent(kind string, ev infra.FsEvent) { switch kind { case "issue": s.handleIssueEvent(ev) case "flow": s.handleFlowEvent(ev) } } func (s *Server) handleIssueEvent(ev infra.FsEvent) { id := issueIDFromPath(ev.Path, s.issuesDir) if id == "" { return } if ev.Op == "remove" || ev.Op == "rename" { s.deleteIssue(id) s.hub.broadcast(SSEEvent{Type: "removed", ID: id, Path: ev.Path}) return } iss, _, err := infra.ParseIssueMd(ev.Path) if err != nil { log.Printf("parse %s: %v", ev.Path, err) return } if err := s.upsertIssueRow(iss); err != nil { log.Printf("upsert %s: %v", iss.ID, err) return } s.hub.broadcast(SSEEvent{Type: "updated", ID: iss.ID, Path: ev.Path}) } func (s *Server) handleFlowEvent(ev infra.FsEvent) { id := issueIDFromPath(ev.Path, s.flowsDir) if id == "" { return } if ev.Op == "remove" || ev.Op == "rename" { s.deleteFlow(id) s.hub.broadcast(SSEEvent{Type: "flow_removed", ID: id, Path: ev.Path}) return } flows, err := infra.ScanFlowsDir(s.flowsDir) if err != nil { log.Printf("scan flows: %v", err) return } for _, fl := range flows { if fl.ID == id { if err := s.upsertFlowRow(fl); err != nil { log.Printf("upsert flow %s: %v", id, err) } s.hub.broadcast(SSEEvent{Type: "flow_updated", ID: id, Path: ev.Path}) return } } }