ref: f0790dd437eba935893e9119102af73c66e38b8c
dir: /cmd/jsfs/main.go/
// 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"
"sync"
)
var (
d *domino.Domino
log *logger.Logger
htm string
js []string
mu sync.Mutex
)
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)
return go9p.ServeReadWriter(r, w, jsFS.Server())
}
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)
mu.Lock()
defer mu.Unlock()
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
}
case "click":
sel, err := r.ReadString('\n')
if err != nil {
log.Errorf("jsfs: click: read string: %v", err)
return
}
sel = strings.TrimSpace(sel)
resHtm, changed, err := d.TriggerClick(sel)
if err != nil {
log.Errorf("track changes: %v", err)
return
}
log.Printf("jsfs: processJS: changed = %v", changed)
if changed {
w.WriteString(resHtm)
w.Flush()
}
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)
}
}