shithub: mycel

Download patch

ref: 5598e0c61213eb2a893bad4625005b72d2b5ecf0
parent: c4be6e0dd0ca49ab1e1535c37888435e6411bb16
author: Philip Silva <philip.silva@protonmail.com>
date: Wed Apr 16 10:50:37 EDT 2025

use DI for js package

--- a/browser/browser.go
+++ b/browser/browser.go
@@ -1520,6 +1520,7 @@
 	history.History
 	dui      *duit.DUI
 	js       *js.JS
+	fs       *fs.FS
 	Website  *Website
 	loading  bool
 	client   *http.Client
@@ -1563,10 +1564,10 @@
 	b.LoadUrl(u)
 
 	if ExperimentalJsInsecure {
-		fs.Client = &http.Client{}
-		fs.Fetcher = b
+		b.fs.Client = &http.Client{}
+		b.fs.Fetcher = b
 	}
-	go fs.Srv9p()
+	go b.fs.Srv9p()
 
 	return
 }
--- a/browser/experimental_test.go
+++ b/browser/experimental_test.go
@@ -19,7 +19,6 @@
 func init() {
 	log.Debug = true
 	style.Init(nil)
-	go fs.Srv9p()
 }
 
 type TestFetcher struct {}
@@ -70,6 +69,8 @@
 		`$('body').hide()`,
 		`throw 'fail';`,
 	}
+	fs := fs.New()
+	go fs.Srv9p()
 	fs.SetDOM(nt)
 	fs.Update("", h, nil, scripts)
 	js.Start(f)
--- a/browser/fs/experimental.go
+++ b/browser/fs/experimental.go
@@ -27,12 +27,13 @@
 //
 // (dir structure stolen from domfs)
 type Node struct {
+	fs   *FS
 	name string
 	nt   *nodes.Node
 }
 
 func (n Node) Stat() (s proto.Stat) {
-	s = *oFS.NewStat(n.name, un, gn, 0700)
+	s = *n.fs.oFS.NewStat(n.name, n.fs.un, n.fs.gn, 0700)
 	s.Mode |= proto.DMDIR
 	// qtype bits should be consistent with Stat mode.
 	s.Qid.Qtype = uint8(s.Mode >> 24)
@@ -58,6 +59,7 @@
 	for i, c := range n.nt.Children {
 		ddn := fmt.Sprintf("%v", i)
 		cs[ddn] = &Node{
+			fs: n.fs,
 			name: ddn,
 			nt:   c,
 		}
@@ -75,7 +77,7 @@
 
 func (n Node) tag() fs.FSNode {
 	return fs.NewDynamicFile(
-		oFS.NewStat("tag", un, gn, 0666),
+		n.fs.oFS.NewStat("tag", n.fs.un, n.fs.gn, 0666),
 		func() []byte {
 			return []byte(n.nt.Data())
 		},
@@ -84,7 +86,7 @@
 
 func (n Node) geom() fs.FSNode {
 	return fs.NewDynamicFile(
-		oFS.NewStat("geom", un, gn, 0666),
+		n.fs.oFS.NewStat("geom", n.fs.un, n.fs.gn, 0666),
 		func() (bs []byte) {
 			var dt style.DomTree
 			if dt = n.nt.Map.DomTree; dt == nil {
@@ -98,7 +100,7 @@
 
 func (n Node) html() fs.FSNode {
 	return fs.NewDynamicFile(
-		oFS.NewStat("html", un, gn, 0666),
+		n.fs.oFS.NewStat("html", n.fs.un, n.fs.gn, 0666),
 		func() []byte {
 			buf := bytes.NewBufferString("")
 			if err := html.Render(buf, n.nt.DomSubtree); err != nil {
@@ -119,11 +121,12 @@
 }
 
 type Attrs struct {
+	n     *Node
 	attrs *[]html.Attribute
 }
 
 func (as Attrs) Stat() (s proto.Stat) {
-	s = *oFS.NewStat("attrs", un, gn, 0500)
+	s = *as.n.fs.oFS.NewStat("attrs", as.n.fs.un, as.n.fs.gn, 0500)
 	s.Mode |= proto.DMDIR
 	// qtype bits should be consistent with Stat mode.
 	s.Qid.Qtype = uint8(s.Mode >> 24)
@@ -146,7 +149,7 @@
 	cs = make(map[string]fs.FSNode)
 	ff := func(k string) fs.FSNode {
 		return fs.NewDynamicFile(
-			oFS.NewStat(k, un, gn, 0666),
+			as.n.fs.oFS.NewStat(k, as.n.fs.un, as.n.fs.gn, 0666),
 			func() []byte {
 				var v string
 				for _, a := range *as.attrs {
@@ -165,11 +168,12 @@
 }
 
 type Style struct {
+	n  *Node
 	cs *style.Map
 }
 
 func (st Style) Stat() (s proto.Stat) {
-	s = *oFS.NewStat("style", un, gn, 0500)
+	s = *st.n.fs.oFS.NewStat("style", st.n.fs.un, st.n.fs.gn, 0500)
 	s.Mode |= proto.DMDIR
 	// qtype bits should be consistent with Stat mode.
 	s.Qid.Qtype = uint8(s.Mode >> 24)
@@ -192,7 +196,7 @@
 	cs = make(map[string]fs.FSNode)
 	ff := func(k string) fs.FSNode {
 		return fs.NewDynamicFile(
-			oFS.NewStat(k, un, gn, 0666),
+			st.n.fs.oFS.NewStat(k, st.n.fs.un, st.n.fs.gn, 0666),
 			func() []byte {
 				var v string
 				for p, d := range st.cs.Declarations {
--- a/browser/fs/fs.go
+++ b/browser/fs/fs.go
@@ -4,7 +4,7 @@
 	"bufio"
 	"encoding/json"
 	"fmt"
-	"github.com/knusbaum/go9p/fs"
+	go9pfs "github.com/knusbaum/go9p/fs"
 	"github.com/knusbaum/go9p/proto"
 	"github.com/psilva261/mycel"
 	"github.com/psilva261/mycel/logger"
@@ -16,35 +16,40 @@
 	"sync"
 )
 
-var (
+type FS struct {
 	mu *sync.RWMutex
 	c  *sync.Cond
 
-	oFS     *fs.FS
+	root     *go9pfs.FS
+	oFS     *go9pfs.FS
 	un      string
 	gn      string
 	url     string
 	htm     string
-	cssDir  *fs.StaticDir
-	jsDir   *fs.StaticDir
+	cssDir  *go9pfs.StaticDir
+	jsDir   *go9pfs.StaticDir
 	rt      *Node
 	Client  *http.Client
 	Fetcher mycel.Fetcher
-)
+}
 
-func init() {
-	mu = &sync.RWMutex{}
-	c = sync.NewCond(mu)
-	SetDOM(nil)
+func New() *FS {
+	fs := &FS{}
+	fs.mu = &sync.RWMutex{}
+	fs.c = sync.NewCond(fs.mu)
+	fs.SetDOM(nil)
+
+	return fs
 }
 
-func SetDOM(d *nodes.Node) {
-	if rt == nil {
-		rt = &Node{
+func (fs *FS) SetDOM(d *nodes.Node) {
+	if fs.rt == nil {
+		fs.rt = &Node{
+			fs:   fs,
 			name: "0",
 		}
 	}
-	rt.nt = d
+	fs.rt.nt = d
 }
 
 func userGroup() (un, gn string, err error) {
@@ -60,74 +65,74 @@
 	return
 }
 
-func Srv9p() {
-	c.L.Lock()
-	var root *fs.StaticDir
+func (fs *FS) Srv9p() {
+	fs.c.L.Lock()
+	var root *go9pfs.StaticDir
 	var err error
 
-	un, gn, err = userGroup()
+	fs.un, fs.gn, err = userGroup()
 	if err != nil {
 		log.Errorf("get user: %v", err)
-		c.L.Unlock()
+		fs.c.L.Unlock()
 		return
 	}
-	oFS, root = fs.NewFS(un, gn, 0500)
-	u := fs.NewDynamicFile(
-		oFS.NewStat("url", un, gn, 0400),
+	fs.oFS, root = go9pfs.NewFS(fs.un, fs.gn, 0500)
+	u := go9pfs.NewDynamicFile(
+		fs.oFS.NewStat("url", fs.un, fs.gn, 0400),
 		func() []byte {
-			mu.RLock()
-			defer mu.RUnlock()
+			fs.mu.RLock()
+			defer fs.mu.RUnlock()
 
-			return []byte(url)
+			return []byte(fs.url)
 		},
 	)
 	root.AddChild(u)
-	h := fs.NewDynamicFile(
-		oFS.NewStat("html", un, gn, 0400),
+	h := go9pfs.NewDynamicFile(
+		fs.oFS.NewStat("html", fs.un, fs.gn, 0400),
 		func() []byte {
-			mu.RLock()
-			defer mu.RUnlock()
+			fs.mu.RLock()
+			defer fs.mu.RUnlock()
 
-			return []byte(htm)
+			return []byte(fs.htm)
 		},
 	)
 	root.AddChild(h)
-	d, err := fs.CreateStaticDir(oFS, root, un, "css", 0500|proto.DMDIR, 0)
+	d, err := go9pfs.CreateStaticDir(fs.oFS, root, fs.un, "css", 0500|proto.DMDIR, 0)
 	if err != nil {
 		log.Errorf("create static dir: %v", err)
-		c.L.Unlock()
+		fs.c.L.Unlock()
 		return
 	}
-	cssDir = d.(*fs.StaticDir)
-	root.AddChild(cssDir)
-	d, err = fs.CreateStaticDir(oFS, root, un, "js", 0500|proto.DMDIR, 0)
+	fs.cssDir = d.(*go9pfs.StaticDir)
+	root.AddChild(fs.cssDir)
+	d, err = go9pfs.CreateStaticDir(fs.oFS, root, fs.un, "js", 0500|proto.DMDIR, 0)
 	if err != nil {
 		log.Errorf("create static dir: %v", err)
-		c.L.Unlock()
+		fs.c.L.Unlock()
 		return
 	}
-	jsDir = d.(*fs.StaticDir)
-	root.AddChild(jsDir)
-	q := fs.NewListenFile(oFS.NewStat("query", un, gn, 0600))
+	fs.jsDir = d.(*go9pfs.StaticDir)
+	root.AddChild(fs.jsDir)
+	q := go9pfs.NewListenFile(fs.oFS.NewStat("query", fs.un, fs.gn, 0600))
 	root.AddChild(q)
-	lq := (*fs.ListenFileListener)(q)
-	root.AddChild(rt)
-	go Query(lq)
-	if Client != nil {
-		xhr := fs.NewListenFile(oFS.NewStat("xhr", un, gn, 0600))
+	lq := (*go9pfs.ListenFileListener)(q)
+	root.AddChild(fs.rt)
+	go fs.Query(lq)
+	if fs.Client != nil {
+		xhr := go9pfs.NewListenFile(fs.oFS.NewStat("xhr", fs.un, fs.gn, 0600))
 		root.AddChild(xhr)
-		lxhr := (*fs.ListenFileListener)(xhr)
-		go Xhr(lxhr)
+		lxhr := (*go9pfs.ListenFileListener)(xhr)
+		go fs.Xhr(lxhr)
 	}
-	c.Broadcast()
-	c.L.Unlock()
+	fs.c.Broadcast()
+	fs.c.L.Unlock()
 
-	if err := post(oFS.Server()); err != nil {
+	if err := post(fs.oFS.Server()); err != nil {
 		log.Errorf("srv9p: %v", err)
 	}
 }
 
-func Query(lq *fs.ListenFileListener) {
+func (fs *FS) Query(lq *go9pfs.ListenFileListener) {
 	for {
 		conn, err := lq.Accept()
 		if err != nil {
@@ -134,11 +139,11 @@
 			log.Errorf("query: accept: %v", err)
 			continue
 		}
-		go query(conn)
+		go fs.query(conn)
 	}
 }
 
-func query(conn net.Conn) {
+func (fs *FS) query(conn net.Conn) {
 	r := bufio.NewReader(conn)
 	enc := json.NewEncoder(conn)
 	defer conn.Close()
@@ -150,11 +155,11 @@
 	}
 	l = strings.TrimSpace(l)
 
-	if rt.nt == nil {
+	if fs.rt.nt == nil {
 		log.Infof("DOM is nil")
 		return
 	}
-	nodes, err := rt.nt.Query(l)
+	nodes, err := fs.rt.nt.Query(l)
 	if err != nil {
 		log.Errorf("query nodes: %v", err)
 		return
@@ -164,7 +169,7 @@
 	}
 }
 
-func Xhr(lxhr *fs.ListenFileListener) {
+func (fs *FS) Xhr(lxhr *go9pfs.ListenFileListener) {
 	for {
 		conn, err := lxhr.Accept()
 		if err != nil {
@@ -171,7 +176,7 @@
 			log.Errorf("xhr: accept: %v", err)
 			continue
 		}
-		go xhr(conn)
+		go fs.xhr(conn)
 	}
 }
 
@@ -183,7 +188,7 @@
 	return alOrig == "*"
 }
 
-func xhr(conn net.Conn) {
+func (fs *FS) xhr(conn net.Conn) {
 	r := bufio.NewReader(conn)
 	defer conn.Close()
 
@@ -196,7 +201,7 @@
 	url := req.URL
 	url.Host = req.Host
 	if h := url.Host; h == "" {
-		url.Host = Fetcher.Origin().Host
+		url.Host = fs.Fetcher.Origin().Host
 	}
 	url.Scheme = "https"
 	proxyReq, err := http.NewRequest(req.Method, url.String(), req.Body)
@@ -210,12 +215,12 @@
 			proxyReq.Header.Add(header, value)
 		}
 	}
-	resp, err := Client.Do(proxyReq)
+	resp, err := fs.Client.Do(proxyReq)
 	if err != nil {
 		log.Errorf("do request: %v", err)
 		return
 	}
-	if h := url.Host; !allowed(resp.Header, h, Fetcher.Origin().Host) {
+	if h := url.Host; !allowed(resp.Header, h, fs.Fetcher.Origin().Host) {
 		log.Errorf("no cross-origin request: %v", h)
 		return
 	}
@@ -225,40 +230,40 @@
 	}
 }
 
-func Update(uri, html string, css []string, js []string) {
-	c.L.Lock()
-	defer c.L.Unlock()
+func (fs *FS) Update(uri, html string, css []string, js []string) {
+	fs.c.L.Lock()
+	defer fs.c.L.Unlock()
 
-	if cssDir == nil && jsDir == nil {
-		c.Wait()
+	if fs.cssDir == nil && fs.jsDir == nil {
+		fs.c.Wait()
 	}
 
-	url = uri
-	htm = html
-	if cssDir != nil {
-		for name := range cssDir.Children() {
-			cssDir.DeleteChild(name)
+	fs.url = uri
+	fs.htm = html
+	if fs.cssDir != nil {
+		for name := range fs.cssDir.Children() {
+			fs.cssDir.DeleteChild(name)
 		}
 		for i, s := range css {
 			fn := fmt.Sprintf("%d.css", i)
-			f := fs.NewStaticFile(
-				oFS.NewStat(fn, un, gn, 0400),
+			f := go9pfs.NewStaticFile(
+				fs.oFS.NewStat(fn, fs.un, fs.gn, 0400),
 				[]byte(s),
 			)
-			cssDir.AddChild(f)
+			fs.cssDir.AddChild(f)
 		}
 	}
-	if jsDir != nil {
-		for name := range jsDir.Children() {
-			jsDir.DeleteChild(name)
+	if fs.jsDir != nil {
+		for name := range fs.jsDir.Children() {
+			fs.jsDir.DeleteChild(name)
 		}
 		for i, s := range js {
 			fn := fmt.Sprintf("%d.js", i)
-			f := fs.NewStaticFile(
-				oFS.NewStat(fn, un, gn, 0400),
+			f := go9pfs.NewStaticFile(
+				fs.oFS.NewStat(fn, fs.un, fs.gn, 0400),
 				[]byte(s),
 			)
-			jsDir.AddChild(f)
+			fs.jsDir.AddChild(f)
 		}
 	}
 }
--- a/browser/website.go
+++ b/browser/website.go
@@ -4,7 +4,7 @@
 	"github.com/mjl-/duit"
 	"github.com/psilva261/mycel"
 	"github.com/psilva261/mycel/browser/duitx"
-	"github.com/psilva261/mycel/browser/fs"
+	//"github.com/psilva261/mycel/browser/fs"
 	"github.com/psilva261/mycel/js"
 	"github.com/psilva261/mycel/logger"
 	"github.com/psilva261/mycel/nodes"
@@ -107,8 +107,8 @@
 			downloads[src] = string(buf)
 		}
 		scripts = js.Scripts(nt, downloads)
-		fs.Update(f.Origin().String(), htm, csss, scripts)
-		fs.SetDOM(nt)
+		w.b.fs.Update(f.Origin().String(), htm, csss, scripts)
+		w.b.fs.SetDOM(nt)
 		log.Infof("JS pipeline start")
 		w.b.js.Stop()
 		w.b.js, jsProcessed, changed, err = processJS2(f)
@@ -163,8 +163,8 @@
 		w.UI = scroller
 	}
 
-	fs.Update(f.Origin().String(), htm, csss, scripts)
-	fs.SetDOM(nt)
+	w.b.fs.Update(f.Origin().String(), htm, csss, scripts)
+	w.b.fs.SetDOM(nt)
 }
 
 func cssSrcs(f mycel.Fetcher, doc *html.Node) (srcs []string) {
--- a/js/js_test.go
+++ b/js/js_test.go
@@ -26,11 +26,10 @@
 
 func init() {
 	log.Debug = true
-	go fs.Srv9p()
-	<-time.After(2*time.Second)
+	<-time.After(2 * time.Second)
 }
 
-type TestFetcher struct {}
+type TestFetcher struct{}
 
 func (tf *TestFetcher) Ctx() context.Context {
 	return context.Background()
@@ -70,6 +69,8 @@
 		t.Fatalf(err.Error())
 	}
 	nt := nodes.NewNodeTree(doc, style.Map{}, make(map[*html.Node]style.Map), nil)
+	fs := fs.New()
+	go fs.Srv9p()
 	fs.SetDOM(nt)
 	fs.Update("", simpleHTML, nil, []string{string(buf), script})