Skip to content

Commit 9a71663

Browse files
committed
implement support for watching /_bull/browse (live reload)
1 parent 29c2d7f commit 9a71663

3 files changed

Lines changed: 35 additions & 9 deletions

File tree

internal/bull/fswatch.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (b *bullServer) watchContentLoop(ctx context.Context, w *fsnotify.Watcher)
111111
}
112112

113113
// handleContentEvent processes a single fsnotify event.
114-
// It returns true if the index was updated (caller should notify).
114+
// It returns true if a content file was affected (caller should notify).
115115
func (b *bullServer) handleContentEvent(w *fsnotify.Watcher, event fsnotify.Event) bool {
116116
name := event.Name
117117

@@ -162,10 +162,9 @@ func (b *bullServer) handleContentEvent(w *fsnotify.Watcher, event fsnotify.Even
162162
case event.Has(fsnotify.Remove) || event.Has(fsnotify.Rename):
163163
// Reading idx outside the lock is a benign TOCTOU: worst case we call
164164
// removeFromIndex redundantly (it rechecks under the lock).
165-
if old := b.idx.Load().links[pageName]; old == nil {
166-
return false // already absent from the index
165+
if old := b.idx.Load().links[pageName]; old != nil {
166+
b.removeFromIndex(pageName)
167167
}
168-
b.removeFromIndex(pageName)
169168
return true
170169

171170
case event.Has(fsnotify.Create) || event.Has(fsnotify.Write):
@@ -181,10 +180,9 @@ func (b *bullServer) handleContentEvent(w *fsnotify.Watcher, event fsnotify.Even
181180
}
182181
// Reading idx outside the lock is a benign TOCTOU: worst case we call
183182
// updateIndex redundantly (it rechecks and stores an identical snapshot).
184-
if slices.Equal(b.idx.Load().links[pageName], targets) {
185-
return false // index already up to date (e.g. save already applied)
183+
if !slices.Equal(b.idx.Load().links[pageName], targets) {
184+
b.updateIndex(pageName, targets)
186185
}
187-
b.updateIndex(pageName, targets)
188186
return true
189187
}
190188
return false

internal/bull/fswatch_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,15 @@ func TestHandleContentEventDedup(t *testing.T) {
134134
Name: filepath.Join(b.contentDir, "alpha.md"),
135135
Op: fsnotify.Write,
136136
})
137-
if updated {
138-
t.Fatal("unchanged targets should not trigger index update")
137+
// handleContentEvent returns true for any markdown file change
138+
// (so watchers like the browse page can reload), but the link
139+
// index itself should not be updated when targets are unchanged.
140+
if !updated {
141+
t.Fatal("markdown write should report content changed")
142+
}
143+
cur := b.idx.Load()
144+
if diff := cmp.Diff(idx.links["alpha"], cur.links["alpha"]); diff != "" {
145+
t.Fatalf("index should not change for unchanged targets (-want +got):\n%s", diff)
139146
}
140147
}
141148

internal/bull/watch.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,22 @@ func maybeNotify(ctx context.Context, notify chan<- struct{}, fileName string) {
6565
}
6666
}
6767

68+
func (b *bullServer) handleWatchBrowse(w http.ResponseWriter, flusher http.Flusher, ctx context.Context) error {
69+
w.Header().Set("Access-Control-Allow-Origin", "*")
70+
initEventStream(w)
71+
for {
72+
contentChanged := b.contentChangedCh()
73+
select {
74+
case <-ctx.Done():
75+
return ctx.Err()
76+
case <-contentChanged:
77+
w.Write([]byte("data: {\"changed\":true}\n\n"))
78+
flusher.Flush()
79+
return nil // client reloads and reconnects
80+
}
81+
}
82+
}
83+
6884
func (b *bullServer) handleWatch(w http.ResponseWriter, r *http.Request) error {
6985
flusher, ok := w.(http.Flusher)
7086
if !ok {
@@ -73,6 +89,11 @@ func (b *bullServer) handleWatch(w http.ResponseWriter, r *http.Request) error {
7389

7490
ctx := r.Context()
7591

92+
pageName := pageFromURL(r)
93+
if pageName == bullPrefix+"browse" {
94+
return b.handleWatchBrowse(w, flusher, ctx)
95+
}
96+
7697
possibilities := filesFromURL(r)
7798
lastb, err := b.readFirst(possibilities)
7899
if err != nil {

0 commit comments

Comments
 (0)