add async updating of the summaries file
2 files changed, 181 insertions(+), 1 deletions(-)

M go.mod
M previewer.go
M go.mod +5 -0
@@ 1,3 1,8 @@ 
 module previewer
 
 go 1.17
+
+require (
+	github.com/fsnotify/fsnotify v1.5.1 // indirect
+	golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
+)

          
M previewer.go +176 -1
@@ 2,12 2,17 @@ package main
 
 import (
 	"encoding/json"
+	"errors"
 	"flag"
 	"fmt"
 	"log"
 	"net/http"
 	"os"
+	"path"
 	"strconv"
+	"sync"
+
+	"github.com/fsnotify/fsnotify"
 )
 
 type Zettel_Summary struct {

          
@@ 20,6 25,11 @@ type Zettel_Summary struct {
 
 type ZK_Summaries map[int]Zettel_Summary
 
+type Safe_ZK_Summaries struct {
+	lock      sync.Mutex
+	summaries ZK_Summaries
+	ready     bool
+}
 type UIDType int
 
 const (

          
@@ 79,6 89,158 @@ func reply(summaries ZK_Summaries, uid s
 	}
 }
 
+func testinotifyfn() {
+	watcher, err := fsnotify.NewWatcher()
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer watcher.Close()
+
+	done := make(chan bool)
+	go func() {
+		for {
+			select {
+			case event, ok := <-watcher.Events:
+				if !ok {
+					return
+				}
+				log.Println("event:", event)
+				log.Println(event.Op)
+			case err, ok := <-watcher.Errors:
+				if !ok {
+					return
+				}
+				log.Println("error:", err)
+
+			}
+		}
+	}()
+
+	err = watcher.Add("./test")
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	<-done
+	log.Println("fin")
+}
+
+func update_summaries(filepath string, mutex_summaries *Safe_ZK_Summaries) {
+	log.Println("Updating...")
+	var summaries ZK_Summaries = read_json_file(filepath)
+	mutex_summaries.lock.Lock()
+	defer mutex_summaries.lock.Unlock()
+	mutex_summaries.summaries = summaries
+	mutex_summaries.ready = true
+}
+
+func watch_dir(filepath string) bool {
+	if _, err := os.Stat(filepath); err == nil {
+		log.Println("File found, not watching directory")
+		return true
+	}
+
+	log.Println("File not found, watching directory.")
+	var dirpath string = path.Dir(filepath)
+	var filename string = path.Base(filepath)
+
+	watcher, err := fsnotify.NewWatcher()
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer watcher.Close()
+
+	done := make(chan bool)
+	go func() {
+		for {
+			select {
+			case event, ok := <-watcher.Events:
+				if !ok {
+					done <- false
+					return
+				}
+				if filename == path.Base(event.Name) && event.Op == fsnotify.Create {
+					log.Println(event)
+					done <- true
+					return
+				}
+			case err, ok := <-watcher.Errors:
+				if !ok {
+					done <- false
+					return
+				}
+				log.Println("error:", err)
+			}
+		}
+	}()
+
+	watcher.Add(dirpath)
+
+	return <-done
+}
+
+func watch_file(filepath string, mu_zk_sum *Safe_ZK_Summaries) bool {
+	if _, err := os.Stat(filepath); errors.Is(err, os.ErrNotExist) {
+		log.Println("File not found, watching directory")
+		return false
+	}
+
+	log.Println("File found, update and watching it.")
+	update_summaries(filepath, mu_zk_sum)
+
+	watcher, err := fsnotify.NewWatcher()
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer watcher.Close()
+
+	done := make(chan bool)
+	go func() {
+		for {
+			select {
+			case event, ok := <-watcher.Events:
+				if !ok {
+					done <- false
+					return
+				}
+				switch event.Op {
+				case fsnotify.Remove, fsnotify.Rename:
+					done <- false
+					return
+				case fsnotify.Create, fsnotify.Write:
+					update_summaries(filepath, mu_zk_sum)
+					break
+				default:
+					log.Println(event)
+				}
+			case err, ok := <-watcher.Errors:
+				if !ok {
+					done <- false
+					return
+				}
+				log.Println("error:", err)
+			}
+		}
+	}()
+
+	watcher.Add(filepath)
+
+	return <-done
+}
+
+func watch(filepath string, mu_zk_sum *Safe_ZK_Summaries) {
+	var filestatus bool = false
+	for {
+		if filestatus {
+			log.Println("Watching file at path", filepath)
+			filestatus = watch_file(filepath, mu_zk_sum)
+		} else {
+			log.Println("Watching dir of", filepath)
+			filestatus = watch_dir(filepath)
+		}
+	}
+}
+
 func main() {
 	var port int
 	var data string

          
@@ 87,13 249,26 @@ func main() {
 
 	flag.Parse()
 
-	var summaries ZK_Summaries = read_json_file(data)
+	var mutex_summaries Safe_ZK_Summaries
+
+	go watch(data, &mutex_summaries)
 
 	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+		var summaries ZK_Summaries
+
+		mutex_summaries.lock.Lock()
+		if mutex_summaries.ready {
+			summaries = mutex_summaries.summaries
+		} else {
+			summaries = nil
+		}
+		mutex_summaries.lock.Unlock()
+
 		code, response := reply(summaries, r.FormValue("id"))
 		w.WriteHeader(code)
 		fmt.Fprintf(w, response)
 	})
 
 	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
+
 }