shithub: mycel

Download patch

ref: ea391fd0eead3ce2ccbfe6594dfc9cf1c6e02b92
parent: 793e9a1d7c697af189320c9e684e5559bb06e3c1
author: Philip Silva <philip.silva@protonmail.com>
date: Tue Jun 1 16:23:02 EDT 2021

Make fs package more thread safe

--- a/browser/fs/fs.go
+++ b/browser/fs/fs.go
@@ -11,7 +11,7 @@
 
 var (
 	log *logger.Logger
-	mu sync.Mutex
+	mu sync.RWMutex
 	oFS *fs.FS
 	un string
 	gn string
@@ -23,49 +23,26 @@
 	log = l
 }
 
-func Update(htm string, js []string) {
-	mu.Lock()
-	defer mu.Unlock()
-
-	html = htm
-
-	for name := range jsDir.Children() {
-		jsDir.DeleteChild(name)
-	}
-	for i, s := range js {
-		fn := fmt.Sprintf("%d.js", i)
-		f := fs.NewStaticFile(
-			oFS.NewStat(fn, un, gn, 0400),
-			[]byte(s),
-		)
-		jsDir.AddChild(f)
-	}
-}
-
-func Srv9p() {
-	if err := srv9p(); err != nil {
-		log.Errorf("srv9p: %v", err)
-	}
-}
-
-func srv9p() (err error) {
+func init() {
 	var root *fs.StaticDir
 
 	u, err := user.Current()
 	if err != nil {
-		return fmt.Errorf("get user: %w", err)
+		log.Errorf("get user: %w", err)
+		return
 	}
 	un = u.Username
 	gn, err = group(u)
 	if err != nil {
-		return fmt.Errorf("get group: %w", err)
+		log.Errorf("get group: %w", err)
+		return
 	}
 	oFS, root = fs.NewFS(un, gn, 0500)
 	h := fs.NewDynamicFile(
 		oFS.NewStat("html", un, gn, 0400),
 		func() []byte {
-			mu.Lock()
-			defer mu.Unlock()
+			mu.RLock()
+			defer mu.RUnlock()
 
 			return []byte(html)
 		},
@@ -73,10 +50,34 @@
 	root.AddChild(h)
 	d, err := fs.CreateStaticDir(oFS, root, un, "js", 0500|proto.DMDIR, 0)
 	if err != nil {
+		log.Errorf("create static dir: %w", err)
 		return
 	}
 	jsDir = d.(*fs.StaticDir)
 	root.AddChild(jsDir)
+}
 
-	return post(oFS.Server())
+func Update(htm string, js []string) {
+	mu.Lock()
+	defer mu.Unlock()
+
+	html = htm
+
+	for name := range jsDir.Children() {
+		jsDir.DeleteChild(name)
+	}
+	for i, s := range js {
+		fn := fmt.Sprintf("%d.js", i)
+		f := fs.NewStaticFile(
+			oFS.NewStat(fn, un, gn, 0400),
+			[]byte(s),
+		)
+		jsDir.AddChild(f)
+	}
+}
+
+func Srv9p() {
+	if err := post(oFS.Server()); err != nil {
+		log.Errorf("srv9p: %v", err)
+	}
 }
--- a/browser/website.go
+++ b/browser/website.go
@@ -12,7 +12,6 @@
 	"github.com/psilva261/opossum/nodes"
 	"github.com/psilva261/opossum/style"
 	"strings"
-	"sync"
 )
 
 const (
@@ -24,26 +23,8 @@
 	duit.UI
 	opossum.ContentType
 	d *domino.Domino
-
-	mu sync.Mutex
-	html string
-	js []string
 }
 
-func (w *Website) Html() string {
-	w.mu.Lock()
-	defer w.mu.Unlock()
-
-	return w.html
-}
-
-func (w *Website) Js() []string {
-	w.mu.Lock()
-	defer w.mu.Unlock()
-
-	return append([]string{}, w.js...)
-}
-
 func (w *Website) layout(f opossum.Fetcher, htm string, layouting int) {
 	defer func() {
 		browser.statusBarMsg("", false)
@@ -99,6 +80,7 @@
 
 	// 3rd pass is only needed initially to load the scripts and set the goja VM
 	// state. During subsequent calls from click handlers that state is kept.
+	var js []string
 	if *ExperimentalJsInsecure && layouting != ClickRelayout {
 		log.Printf("3rd pass")
 		nt := nodes.NewNodeTree(doc, style.Map{}, nodeMap, nil)
@@ -118,10 +100,7 @@
 			}
 			downloads[src] = string(buf)
 		}
-		codes := domino.Scripts(nt, downloads)
-		w.mu.Lock()
-		w.js = append([]string{}, codes...)
-		w.mu.Unlock()
+		js = domino.Scripts(nt, downloads)
 		log.Infof("JS pipeline start")
 		if w.d != nil {
 			log.Infof("Stop existing JS instance")
@@ -129,7 +108,7 @@
 		}
 		w.d = domino.NewDomino(htm, browser, nt)
 		w.d.Start()
-		jsProcessed, changed, err := processJS2(w.d, codes)
+		jsProcessed, changed, err := processJS2(w.d, js)
 		if changed && err == nil {
 			htm = jsProcessed
 			if debugPrintHtml {
@@ -171,10 +150,7 @@
 		w.UI = scroller
 	}
 
-	w.mu.Lock()
-	w.html = htm
-	w.mu.Unlock()
-	fs.Update(w.html, w.js)
+	fs.Update(htm, js)
 
 	log.Flush()
 }