215 lines
4.8 KiB
Go
215 lines
4.8 KiB
Go
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,
|
|
})
|
|
}
|