package client import ( _ "embed" "strings" "sync" "time" "apigo.cc/gojs" "apigo.cc/gojs/goja" "github.com/ssgo/tool/watcher" ) // TODO 桌面应用使用 https://github.com/neutralinojs/neutralinojs // TODO App使用 https://pkg.go.dev/golang.org/x/mobile/cmd/gomobile //go:embed client.ts var clientTS string //go:embed README.md var clientMD string //go:embed app.js var appCode string var binds = map[string]any{} var bindsLock = sync.RWMutex{} var windowsId uint64 var windows = map[uint64]*Webview{} var windowsLock = sync.RWMutex{} var waitChan chan bool func Bind(name string, fn any) { bindsLock.Lock() binds[name] = fn bindsLock.Unlock() } func Unbind(name string) { bindsLock.Lock() delete(binds, name) bindsLock.Unlock() } func Wait() { // 如果有窗口在运行,等待窗口关闭 windowsLock.RLock() if len(windows) > 0 { waitChan = make(chan bool, 1) } windowsLock.RUnlock() // fmt.Println("====== wait start") if waitChan != nil { <-waitChan waitChan = nil } // fmt.Println("====== wait end") } func CloseAll() { windows1 := map[uint64]*Webview{} windowsLock.Lock() for id, w := range windows { windows1[id] = w } windowsLock.Unlock() for _, w := range windows1 { w.close() } } func (w *Webview) SetTitle(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { args := gojs.MakeArgs(&argsIn, vm).Check(1) w.setTitle(args.Str(0)) return nil } func (w *Webview) SetSize(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { args := gojs.MakeArgs(&argsIn, vm).Check(2) w.setSize(args.Int(0), args.Int(1), args.Str(2)) return nil } func (w *Webview) Eval(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { args := gojs.MakeArgs(&argsIn, vm).Check(1) w.eval(args.Str(0)) return nil } func (w *Webview) Close(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { w.close() return nil } func (w *Webview) LoadHtml(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { args := gojs.MakeArgs(&argsIn, vm).Check(1) w.loadHtml(args.Str(0)) return nil } func (w *Webview) LoadURL(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { args := gojs.MakeArgs(&argsIn, vm).Check(1) w.loadURL(args.Str(0)) return nil } func init() { obj := map[string]any{ "open": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { args := gojs.MakeArgs(&argsIn, vm) title := "" width := 800 height := 600 sizeMode := "none" isDebug := false html := "" url := "" if opt := args.Obj(0); opt != nil { if titleV := opt.Str("title"); titleV != "" { title = titleV } if widthV := opt.Int("width"); widthV != 0 { width = widthV } if heightV := opt.Int("height"); heightV != 0 { height = heightV } if sizeModeV := opt.Str("sizeMode"); sizeModeV != "" { sizeMode = sizeModeV } if isDebugV := opt.Bool("isDebug"); isDebugV { isDebug = isDebugV } if htmlV := opt.Str("html"); htmlV != "" { html = htmlV } if urlV := opt.Str("url"); urlV != "" { url = urlV if strings.HasPrefix(url, "file://") { url = url[7:] } } } w := &Webview{isDebug: isDebug, html: html, url: url} // startChan := make(chan bool, 1) // fmt.Println("====== start") gojs.RunInMain(func() { // fmt.Println("====== gojs.RunInMain") windowsLock.Lock() w.id = windowsId windowsId++ windows[w.id] = w windowsLock.Unlock() // fmt.Println("====== w.New()") w.New(isDebug) // fmt.Println("====== 1") w.setTitle(title) // fmt.Println("====== 2") w.setSize(width, height, sizeMode) // fmt.Println("====== 3") w.binds() // fmt.Println("====== w.Run()") if w.isDebug { var isWaitingRun = false if w.webRoot == "" && w.html != "" { w.webRoot = "." } if w.webRoot != "" { w.watcher, _ = watcher.Start([]string{w.webRoot}, []string{"html", "js", "css"}, nil, func(filename string, event string) { if !isWaitingRun { isWaitingRun = true go func() { time.Sleep(time.Millisecond * 10) isWaitingRun = false w.eval("location.reload()") }() } }) } } w.isRunning = true // fmt.Println("====== w.reload()") w.reload() // startChan <- true // fmt.Println("====== w.Run()") w.Run() // fmt.Println("====== w.Run() end") w.doClose() }) // <-startChan return vm.ToValue(gojs.MakeMap(w)) }, "closeAll": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { CloseAll() return nil }, } gojs.Register("apigo.cc/gojs/client", gojs.Module{ Object: obj, Desc: "web client framework by github.com/chromedp/chromedp or github.com/webview/webview", TsCode: clientTS, Example: clientMD, WaitForStop: Wait, OnKill: CloseAll, }) }