ref: 4653bf4759b83714a4931d28cecd01f6a7d95533
parent: 73c38e317976971341f58ebd74c568203cdfea1f
author: Philip Silva <philip.silva@protonmail.com>
date: Sun Jun 20 14:14:40 EDT 2021
cmd/jsfs
--- a/.gitignore
+++ b/.gitignore
@@ -9,4 +9,5 @@
~*
.DS_Store
/cmd/browse/browse
+/cmd/jsfs/jsfs
main.js
--- a/browser/fs/fs.go
+++ b/browser/fs/fs.go
@@ -6,6 +6,7 @@
"fmt"
"github.com/knusbaum/go9p/fs"
"github.com/knusbaum/go9p/proto"
+ "github.com/psilva261/opossum"
"github.com/psilva261/opossum/logger"
"github.com/psilva261/opossum/nodes"
"net"
@@ -43,7 +44,7 @@
return
}
un = u.Username
- gn, err = group(u)
+ gn, err = opossum.Group(u)
if err != nil {
log.Errorf("get group: %v", err)
return
--- a/browser/fs/fs_plan9.go
+++ b/browser/fs/fs_plan9.go
@@ -4,20 +4,15 @@
"fmt"
"github.com/knusbaum/go9p"
"os"
- "os/user"
"syscall"
)
-func group(u *user.User) (string, error) {
- return u.Gid, nil
-}
-
func post(srv go9p.Srv) (err error) {
f1, f2, err := os.Pipe()
if err != nil {
return fmt.Errorf("pipe: %w", err)
}
-
+
go func() {
err = go9p.ServeReadWriter(f1, f1, srv)
if err != nil {
--- a/browser/fs/fs_unix.go
+++ b/browser/fs/fs_unix.go
@@ -3,18 +3,8 @@
package fs
import (
- "fmt"
"github.com/knusbaum/go9p"
- "os/user"
)
-
-func group(u *user.User) (string, error) {
- g, err := user.LookupGroupId(u.Gid)
- if err != nil {
- return "", fmt.Errorf("get group: %w", err)
- }
- return g.Name, nil
-}
func post(srv go9p.Srv) (err error) {
return go9p.PostSrv("opossum", srv)
--- a/cmd/devjs/main.go
+++ /dev/null
@@ -1,133 +1,0 @@
-// js package as separate program (very wip)
-package main
-
-import (
- "encoding/json"
- "fmt"
- "github.com/psilva261/opossum/domino"
- "github.com/psilva261/opossum/domino/jsfcall"
- "github.com/psilva261/opossum/logger"
- "io"
- "os"
- "strings"
-)
-
-var (
- d *domino.Domino
- log *logger.Logger
-)
-
-func init() {
- f := false
- t := true
- domino.DebugDumpJS = &t
- logger.Quiet = &f
- logger.Init()
- log = &logger.Logger{Debug: true}
- domino.SetLogger(log)
-}
-
-func usage() {
- log.Printf("usage: devjs -h htmlfile jsfile1 [jsfile2 [..]]")
- os.Exit(1)
-}
-
-func Main(r io.Reader, w io.Writer, htm string, js []string) error {
- msg := jsfcall.Msg{}
- dec := json.NewDecoder(r)
- enc := json.NewEncoder(w)
-
- for {
- err := dec.Decode(&msg)
- if err == io.EOF {
- if d != nil {
- // TODO: probably that's not even necessary
- d.Stop()
- }
- break
- }
- if err != nil {
- return fmt.Errorf("decode: %v", err)
- }
-
- switch msg.Type {
- case jsfcall.Tinit:
- log.Printf("received Tinit")
- log.Printf("htm=%v", htm)
- d = domino.NewDomino(htm, nil, nil)
- d.Start()
- initialized := false
- for _, s := range js {
- if _, err := d.Exec/*6*/(s, !initialized); err != nil {
- if strings.Contains(err.Error(), "halt at") {
- return fmt.Errorf("execution halted: %w", err)
- }
- log.Printf("exec <script>: %v", err)
- }
- initialized = true
- }
- if err := d.CloseDoc(); err != nil {
- return fmt.Errorf("close doc: %w", err)
- }
- resHtm, changed, err := d.TrackChanges()
- if err == nil {
- log.Printf("processJS: changed = %v", changed)
- } else {
- return fmt.Errorf("track changes: %w", err)
- }
- msg := &jsfcall.Msg{
- Type: jsfcall.Rinit,
- Html: resHtm,
- }
- if err := enc.Encode(&msg); err != nil {
- return fmt.Errorf("encode: %v", err)
- }
- default:
- return fmt.Errorf("unhandled msg: %+v", msg)
- }
- }
-
- return nil
-}
-
-func main() {
- args := os.Args[1:]
- if len(args) == 0 {
- usage()
- }
-
- htmlfile := ""
- jsfiles := make([]string, 0, len(args))
-
- for len(args) > 0 {
- switch args[0] {
- case "-h":
- htmlfile, args = args[1], args[2:]
- default:
- var jsfile string
- jsfile, args = args[0], args[1:]
- jsfiles = append(jsfiles, jsfile)
- }
- }
-
- htm := ""
- js := make([]string, 0, len(jsfiles))
- if htmlfile != "" {
- b, err := os.ReadFile(htmlfile)
- if err != nil {
- log.Fatalf(err.Error())
- }
- htm = string(b)
- }
- for _, jsfile := range jsfiles {
- b, err := os.ReadFile(jsfile)
- if err != nil {
- log.Fatalf(err.Error())
- }
- js = append(js, string(b))
- }
-
- if err := Main(os.Stdin, os.Stdout, htm, js); err != nil {
- log.Fatalf("Main: %+v", err)
- }
-}
--- /dev/null
+++ b/cmd/jsfs/main.go
@@ -1,0 +1,168 @@
+// js package as separate program (very wip)
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "github.com/knusbaum/go9p"
+ "github.com/knusbaum/go9p/fs"
+ "github.com/psilva261/opossum"
+ "github.com/psilva261/opossum/domino"
+ "github.com/psilva261/opossum/logger"
+ "io"
+ "net"
+ "os"
+ "os/user"
+ "strings"
+)
+
+var (
+ d *domino.Domino
+ log *logger.Logger
+ htm string
+ js []string
+)
+
+func init() {
+ f := false
+ t := true
+ domino.DebugDumpJS = &t
+ logger.Quiet = &f
+ logger.Init()
+ log = &logger.Logger{Debug: true}
+ domino.SetLogger(log)
+}
+
+func usage() {
+ log.Printf("usage: jsfs -h htmlfile jsfile1 [jsfile2 [..]]")
+ os.Exit(1)
+}
+
+func Main(r io.Reader, w io.Writer) (err error) {
+ u, err := user.Current()
+ if err != nil {
+ return fmt.Errorf("get user: %v", err)
+ }
+ un := u.Username
+ gn, err := opossum.Group(u)
+ if err != nil {
+ return fmt.Errorf("get group: %v", err)
+ }
+
+ jsFS, root := fs.NewFS(un, gn, 0500)
+ c := fs.NewListenFile(jsFS.NewStat("ctl", un, gn, 0600))
+ root.AddChild(c)
+ lctl := (*fs.ListenFileListener)(c)
+ go Ctl(lctl)
+ go func() {
+ err := go9p.ServeReadWriter(r, w, jsFS.Server())
+ if err != nil {
+ log.Errorf("jsfs: serve rw: %v", err)
+ }
+ }()
+
+ return
+}
+
+func Ctl(lctl *fs.ListenFileListener) {
+ for {
+ conn, err := lctl.Accept()
+ if err != nil {
+ log.Errorf("accept: %v", err)
+ continue
+ }
+ go ctl(conn)
+ }
+}
+
+func ctl(conn net.Conn) {
+ r := bufio.NewReader(conn)
+ w := bufio.NewWriter(conn)
+ defer conn.Close()
+
+ l, err := r.ReadString('\n')
+ if err != nil {
+ log.Errorf("jsfs: read string: %v", err)
+ return
+ }
+ l = strings.TrimSpace(l)
+
+ switch l {
+ case "start":
+ d = domino.NewDomino(htm, nil, nil)
+ d.Start()
+ initialized := false
+ for _, s := range js {
+ if _, err := d.Exec(s, !initialized); err != nil {
+ if strings.Contains(err.Error(), "halt at") {
+ log.Errorf("execution halted: %v", err)
+ return
+ }
+ log.Printf("exec <script>: %v", err)
+ }
+ initialized = true
+ }
+ if err := d.CloseDoc(); err != nil {
+ log.Errorf("close doc: %v", err)
+ return
+ }
+ resHtm, changed, err := d.TrackChanges()
+ if err != nil {
+ log.Errorf("track changes: %v", err)
+ return
+ }
+ log.Printf("jsfs: processJS: changed = %v", changed)
+ if changed {
+ w.WriteString(resHtm)
+ w.Flush()
+ }
+ case "stop":
+ if d != nil {
+ d.Stop()
+ d = nil
+ }
+ default:
+ log.Errorf("unknown cmd")
+ }
+}
+
+func main() {
+ args := os.Args[1:]
+ if len(args) == 0 {
+ usage()
+ }
+
+ htmlfile := ""
+ jsfiles := make([]string, 0, len(args))
+
+ for len(args) > 0 {
+ switch args[0] {
+ case "-h":
+ htmlfile, args = args[1], args[2:]
+ default:
+ var jsfile string
+ jsfile, args = args[0], args[1:]
+ jsfiles = append(jsfiles, jsfile)
+ }
+ }
+
+ js = make([]string, 0, len(jsfiles))
+ if htmlfile != "" {
+ b, err := os.ReadFile(htmlfile)
+ if err != nil {
+ log.Fatalf(err.Error())
+ }
+ htm = string(b)
+ }
+ for _, jsfile := range jsfiles {
+ b, err := os.ReadFile(jsfile)
+ if err != nil {
+ log.Fatalf(err.Error())
+ }
+ js = append(js, string(b))
+ }
+
+ if err := Main(os.Stdin, os.Stdout); err != nil {
+ log.Fatalf("Main: %+v", err)
+ }
+}
--- /dev/null
+++ b/cmd/jsfs/main_test.go
@@ -1,0 +1,61 @@
+package main
+
+import (
+ "9fans.net/go/plan9"
+ "9fans.net/go/plan9/client"
+ "bytes"
+ "io"
+ "bufio"
+ "net"
+ "os/user"
+ "strings"
+ "testing"
+)
+
+func TestMain(t *testing.T) {
+ u, err := user.Current()
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ un := u.Username
+ c1, c2 := net.Pipe()
+ err = Main(c1, c1)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ conn, err := client.NewConn(c2)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ fsys, err := conn.Attach(nil, un, "")
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ d, err := fsys.Stat("ctl")
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ if d.Name != "ctl" {
+ t.Fail()
+ }
+ htm = "<html><h1 id=title>hello</h1></html>"
+ js = []string{
+ "document.getElementById('title').innerHTML='world'",
+ }
+ fid, err := fsys.Open("ctl", plan9.ORDWR)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ defer fid.Close()
+ fid.Write([]byte("start\n"))
+ r := bufio.NewReader(fid)
+ b := bytes.NewBuffer([]byte{})
+ _, err = io.Copy(b, r)
+ if !strings.Contains(err.Error(), io.ErrClosedPipe.Error()) {
+ t.Fatalf("%+v", err)
+ }
+ t.Logf("%v", b.String())
+ if !strings.Contains(b.String(), `<h1 id="title">world</h1>`) {
+ t.Fail()
+ }
+}
--- a/domino/jsfcall/jsfcall.go
+++ /dev/null
@@ -1,17 +1,0 @@
-package jsfcall
-
-const (
- _ = iota
- Rerror
- Tinit
- Rinit
- Tclick
- Rclick
-)
-
-type Msg struct {
- Type uint8
- Error string
- Changed bool
- Html string
-}
--- /dev/null
+++ b/opossum_plan9.go
@@ -1,0 +1,9 @@
+package opossum
+
+import (
+ "os/user"
+)
+
+func Group(u *user.User) (string, error) {
+ return u.Gid, nil
+}
--- /dev/null
+++ b/opossum_unix.go
@@ -1,0 +1,16 @@
+// +build !plan9
+
+package opossum
+
+import (
+ "fmt"
+ "os/user"
+)
+
+func Group(u *user.User) (string, error) {
+ g, err := user.LookupGroupId(u.Gid)
+ if err != nil {
+ return "", fmt.Errorf("get group: %w", err)
+ }
+ return g.Name, nil
+}