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})