261024.23 · 9ceefbd589221fc686c18d0278d9074fe465fe79
make run opens a browser only when no page of the tree is open
--restart takes a directory: after replacing the servers it serves the directory and opens it unless a page of it held a live stream to the old server. The restart asks the stopping server for its open pages through a record in the registry, and says how many reload onto each new server. make run is now one --restart call, so a Delete lock click no longer decides whether a tab opens.
reading declarations
Changes to live.go. All files
@@ -58,26 +58,26 @@ type live struct { key []byte // keys versions, which pages show to visitors w *watcher mu sync.Mutex- subs map[chan struct{}]bool- wds map[int]int // open pages per watch descriptor+ subs map[chan struct{}]string // each open page's stream, to the page's path+ wds map[int]int // open pages per watch descriptor done chan struct{} once sync.Once } func newLive() *live {- l := &live{id: rand.Text()[:12], key: []byte(rand.Text()), w: newWatcher(pageMask), subs: map[chan struct{}]bool{},+ l := &live{id: rand.Text()[:12], key: []byte(rand.Text()), w: newWatcher(pageMask), subs: map[chan struct{}]string{}, wds: map[int]int{}, done: make(chan struct{})} go l.loop() return l } -// subscribe watches dirs for one page and returns the channel that wakes-// it. release undoes both.-func (l *live) subscribe(dirs []string) (wake chan struct{}, release func()) {+// subscribe watches dirs for the page at path and returns the channel that+// wakes it. release undoes both.+func (l *live) subscribe(path string, dirs []string) (wake chan struct{}, release func()) { wake = make(chan struct{}, 1) var wds []int l.mu.Lock()- l.subs[wake] = true+ l.subs[wake] = path for _, dir := range dirs { // A directory reached twice, through a link, has one descriptor. if wd := l.w.add(dir); wd >= 0 && !slices.Contains(wds, wd) {@@ -134,6 +134,21 @@ func (l *live) loop() { } } +// pages returns the path of each page that holds a stream, one entry per+// page, so two tabs on one path count twice.+func (l *live) pages() []string {+ if l == nil {+ return nil+ }+ l.mu.Lock()+ defer l.mu.Unlock()+ paths := make([]string, 0, len(l.subs))+ for _, p := range l.subs {+ paths = append(paths, p)+ }+ return paths+}+ // kick wakes every page, as when a tree joins or leaves. func (l *live) kick() { if l != nil {@@ -182,7 +197,7 @@ func (s *server) handleLive(w http.ResponseWriter, r *http.Request) { return } p, seen := r.URL.Query().Get("path"), r.URL.Query().Get("v")- wake, release := l.subscribe(s.watchDirs(p))+ wake, release := l.subscribe(p, s.watchDirs(p)) defer release() w.Header().Set("Content-Type", "text/event-stream") // A dropped stream comes back after a second, as on --restart. One lost