add __startExec、__runFile
add Watch for custom watch action fix bug of WatchRun
This commit is contained in:
parent
2832100201
commit
e9c25edc20
235
gojs.go
235
gojs.go
@ -98,20 +98,25 @@ func WaitAll() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
modulesLock.RUnlock()
|
modulesLock.RUnlock()
|
||||||
|
stopped := false
|
||||||
sigCh := make(chan os.Signal, 1)
|
sigCh := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP)
|
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP)
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case sig := <-sigCh:
|
case sig := <-sigCh:
|
||||||
|
if stopped {
|
||||||
|
break
|
||||||
|
}
|
||||||
// send signal
|
// send signal
|
||||||
for _, fn := range onSignals {
|
for _, fn := range onSignals {
|
||||||
fn(sig)
|
fn(sig)
|
||||||
}
|
}
|
||||||
// kill
|
// kill
|
||||||
if sig == syscall.SIGINT || sig == syscall.SIGTERM {
|
if sig == syscall.SIGINT || sig == syscall.SIGTERM {
|
||||||
WatcherOnKill()
|
if wr != nil {
|
||||||
|
wr.Stop()
|
||||||
|
}
|
||||||
for _, fn := range onKills {
|
for _, fn := range onKills {
|
||||||
fn()
|
fn()
|
||||||
}
|
}
|
||||||
@ -120,11 +125,13 @@ func WaitAll() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// 一些必须在主线程运行的代码在这运行(例如 apigo.cc/gojs/client)
|
// 一些必须在主线程运行的代码在这运行(例如 apigo.cc/gojs/client)
|
||||||
for _, fn := range runInMainFuncs {
|
for _, fn := range runInMainFuncs {
|
||||||
fn()
|
fn()
|
||||||
}
|
}
|
||||||
|
if wr != nil {
|
||||||
|
wr.Wait()
|
||||||
|
}
|
||||||
if len(waits) > 0 {
|
if len(waits) > 0 {
|
||||||
waitChan := make(chan bool, len(waits))
|
waitChan := make(chan bool, len(waits))
|
||||||
for _, fn := range waits {
|
for _, fn := range waits {
|
||||||
@ -134,6 +141,8 @@ func WaitAll() {
|
|||||||
}(fn)
|
}(fn)
|
||||||
}
|
}
|
||||||
<-waitChan
|
<-waitChan
|
||||||
|
stopped = true
|
||||||
|
sigCh <- syscall.SIGTERM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,10 +164,10 @@ func Run(code string, refFile string, args ...any) (any, error) {
|
|||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunProgram(plg *Program, args ...any) (any, error) {
|
func RunProgram(prg *Program, args ...any) (any, error) {
|
||||||
rt := New()
|
rt := New()
|
||||||
var r any
|
var r any
|
||||||
err := rt.StartFromProgram(plg)
|
err := rt.StartFromProgram(prg)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
r, err = rt.RunMain(args...)
|
r, err = rt.RunMain(args...)
|
||||||
}
|
}
|
||||||
@ -345,6 +354,7 @@ func New() *Runtime {
|
|||||||
vm: vm,
|
vm: vm,
|
||||||
required: map[string]bool{},
|
required: map[string]bool{},
|
||||||
}
|
}
|
||||||
|
vm.Set("__startExec", os.Args[0])
|
||||||
|
|
||||||
vm.GoData = map[string]any{
|
vm.GoData = map[string]any{
|
||||||
"logger": log.New(u.ShortUniqueId()),
|
"logger": log.New(u.ShortUniqueId()),
|
||||||
@ -402,6 +412,7 @@ func (rt *Runtime) StartFromCode(code, refFile string) error {
|
|||||||
refPath := filepath.Dir(refFile)
|
refPath := filepath.Dir(refFile)
|
||||||
rt.SetGoData("startFile", refFile)
|
rt.SetGoData("startFile", refFile)
|
||||||
rt.SetGoData("startPath", refPath)
|
rt.SetGoData("startPath", refPath)
|
||||||
|
rt.vm.Set("__startFile", refFile)
|
||||||
|
|
||||||
if rt.srcCode == "" {
|
if rt.srcCode == "" {
|
||||||
rt.srcCode = code
|
rt.srcCode = code
|
||||||
@ -434,6 +445,7 @@ func (rt *Runtime) StartFromCode(code, refFile string) error {
|
|||||||
rt.code = "function main(...Args){" + rt.code + "}"
|
rt.code = "function main(...Args){" + rt.code + "}"
|
||||||
}
|
}
|
||||||
rt.lock()
|
rt.lock()
|
||||||
|
rt.vm.Set("__runFile", rt.file)
|
||||||
_, err := rt.vm.RunScript(rt.file, rt.code)
|
_, err := rt.vm.RunScript(rt.file, rt.code)
|
||||||
rt.unlock()
|
rt.unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -444,20 +456,22 @@ func (rt *Runtime) StartFromCode(code, refFile string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) StartFromProgram(plg *Program) error {
|
func (rt *Runtime) StartFromProgram(prg *Program) error {
|
||||||
var modErr error
|
var modErr error
|
||||||
if len(plg.imports) == 0 {
|
if len(prg.imports) == 0 {
|
||||||
modErr = rt.requireAllMod()
|
modErr = rt.requireAllMod()
|
||||||
} else {
|
} else {
|
||||||
modErr = rt.setImports(plg.imports)
|
modErr = rt.setImports(prg.imports)
|
||||||
}
|
}
|
||||||
if modErr != nil {
|
if modErr != nil {
|
||||||
return modErr
|
return modErr
|
||||||
}
|
}
|
||||||
rt.SetGoData("startFile", plg.startFile)
|
rt.SetGoData("startFile", prg.startFile)
|
||||||
rt.SetGoData("startPath", filepath.Dir(plg.startFile))
|
rt.SetGoData("startPath", filepath.Dir(prg.startFile))
|
||||||
rt.lock()
|
rt.lock()
|
||||||
_, err := rt.vm.RunProgram(plg.prg)
|
rt.vm.Set("__startFile", prg.startFile)
|
||||||
|
rt.vm.Set("__runFile", prg.startFile)
|
||||||
|
_, err := rt.vm.RunProgram(prg.prg)
|
||||||
rt.unlock()
|
rt.unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -538,6 +552,7 @@ func (rt *Runtime) RunFile(file string) (any, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rt.lock()
|
rt.lock()
|
||||||
|
rt.vm.Set("__runFile", file)
|
||||||
r, err := rt.vm.RunScript(file, code)
|
r, err := rt.vm.RunScript(file, code)
|
||||||
rt.unlock()
|
rt.unlock()
|
||||||
return makeResult(r, err)
|
return makeResult(r, err)
|
||||||
@ -562,6 +577,7 @@ func (rt *Runtime) RunProgram(prg *Program) (any, error) {
|
|||||||
err := rt.setImports(prg.imports)
|
err := rt.setImports(prg.imports)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
rt.lock()
|
rt.lock()
|
||||||
|
rt.vm.Set("__runFile", prg.startFile)
|
||||||
r, err = rt.vm.RunProgram(prg.prg)
|
r, err = rt.vm.RunProgram(prg.prg)
|
||||||
rt.unlock()
|
rt.unlock()
|
||||||
}
|
}
|
||||||
@ -579,13 +595,8 @@ func makeResult(r goja.Value, err error) (any, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WatchRunner struct {
|
type WatchRunner struct {
|
||||||
w *watcher.Watcher
|
w *watcher.Watcher
|
||||||
}
|
stopCh chan bool
|
||||||
|
|
||||||
func WatcherOnKill() {
|
|
||||||
if wr != nil {
|
|
||||||
wr.Stop()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (wr *WatchRunner) WaitForKill() {
|
// func (wr *WatchRunner) WaitForKill() {
|
||||||
@ -600,34 +611,79 @@ func WatcherOnKill() {
|
|||||||
// wr.w.Stop()
|
// wr.w.Stop()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
func (wr *WatchRunner) Wait() {
|
||||||
|
<-wr.stopCh
|
||||||
|
}
|
||||||
|
|
||||||
func (wr *WatchRunner) Stop() {
|
func (wr *WatchRunner) Stop() {
|
||||||
wr.w.Stop()
|
wr.w.Stop()
|
||||||
|
wr.stopCh <- true
|
||||||
wr = nil
|
wr = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (wr *WatchRunner) SetModuleLoader(rt *Runtime) {
|
||||||
|
rt.SetModuleLoader(func(filename string) string {
|
||||||
|
filePath := filepath.Dir(filename)
|
||||||
|
needWatch := true
|
||||||
|
for _, v := range wr.w.WatchList() {
|
||||||
|
if v == filePath {
|
||||||
|
needWatch = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if needWatch {
|
||||||
|
fmt.Println(u.BMagenta("[watching module path]"), filePath)
|
||||||
|
_ = wr.w.Add(filePath)
|
||||||
|
}
|
||||||
|
return u.ReadFileN(filename)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var wr *WatchRunner
|
var wr *WatchRunner
|
||||||
|
|
||||||
func WatchRun(file string, extDirs, extTypes []string, args ...any) (*WatchRunner, error) {
|
func Watch(files, types []string, onRun func([]string)) (*WatchRunner, error) {
|
||||||
wr = &WatchRunner{}
|
wr = &WatchRunner{}
|
||||||
run := func() {
|
var isWaitingRun = false
|
||||||
rt := New()
|
changes := make([]string, 0)
|
||||||
if wr.w != nil {
|
changesLock := sync.Mutex{}
|
||||||
rt.SetModuleLoader(func(filename string) string {
|
onChange := func(filename string, event string) {
|
||||||
filePath := filepath.Dir(filename)
|
changesLock.Lock()
|
||||||
needWatch := true
|
changes = append(changes, filename)
|
||||||
for _, v := range wr.w.WatchList() {
|
changesLock.Unlock()
|
||||||
if v == filePath {
|
if !isWaitingRun {
|
||||||
needWatch = false
|
_, _ = os.Stdout.WriteString("\x1b[3;J\x1b[H\x1b[2J")
|
||||||
break
|
isWaitingRun = true
|
||||||
}
|
go func() {
|
||||||
}
|
time.Sleep(time.Millisecond * 10)
|
||||||
if needWatch {
|
isWaitingRun = false
|
||||||
fmt.Println(u.BMagenta("[watching module path]"), filePath)
|
changesLock.Lock()
|
||||||
_ = wr.w.Add(filePath)
|
changes2 := make([]string, len(changes))
|
||||||
}
|
copy(changes2, changes)
|
||||||
return u.ReadFileN(filename)
|
changes = make([]string, 0)
|
||||||
})
|
changesLock.Unlock()
|
||||||
|
onRun(changes2)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
fmt.Println(u.BYellow("[changed]"), filename)
|
||||||
|
}
|
||||||
|
_, _ = os.Stdout.WriteString("\x1b[3;J\x1b[H\x1b[2J")
|
||||||
|
if w, err := watcher.Start(files, types, onChange); err == nil {
|
||||||
|
wr.w = w
|
||||||
|
go func() {
|
||||||
|
onRun(changes)
|
||||||
|
}()
|
||||||
|
wr.stopCh = make(chan bool, 1)
|
||||||
|
return wr, nil
|
||||||
|
} else {
|
||||||
|
wr = nil
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WatchRun(file string, args ...any) (*WatchRunner, error) {
|
||||||
|
return Watch([]string{file}, []string{"js", "json", "yml"}, func(files []string) {
|
||||||
|
rt := New()
|
||||||
|
wr.SetModuleLoader(rt)
|
||||||
err := rt.StartFromFile(file)
|
err := rt.StartFromFile(file)
|
||||||
result, err := rt.RunMain(args...)
|
result, err := rt.RunMain(args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -636,45 +692,74 @@ func WatchRun(file string, extDirs, extTypes []string, args ...any) (*WatchRunne
|
|||||||
} else if result != nil {
|
} else if result != nil {
|
||||||
fmt.Println(u.Cyan(u.JsonP(result)))
|
fmt.Println(u.Cyan(u.JsonP(result)))
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
// wr = &WatchRunner{}
|
||||||
|
// run := func() {
|
||||||
|
// rt := New()
|
||||||
|
// if wr.w != nil {
|
||||||
|
// rt.SetModuleLoader(func(filename string) string {
|
||||||
|
// filePath := filepath.Dir(filename)
|
||||||
|
// needWatch := true
|
||||||
|
// for _, v := range wr.w.WatchList() {
|
||||||
|
// if v == filePath {
|
||||||
|
// needWatch = false
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if needWatch {
|
||||||
|
// fmt.Println(u.BMagenta("[watching module path]"), filePath)
|
||||||
|
// _ = wr.w.Add(filePath)
|
||||||
|
// }
|
||||||
|
// return u.ReadFileN(filename)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// err := rt.StartFromFile(file)
|
||||||
|
// result, err := rt.RunMain(args...)
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.Println(u.BRed(err.Error()))
|
||||||
|
// fmt.Println(u.Red(" " + strings.Join(rt.GetCallStack(), "\n ")))
|
||||||
|
// } else if result != nil {
|
||||||
|
// fmt.Println(u.Cyan(u.JsonP(result)))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
var isWaitingRun = false
|
// var isWaitingRun = false
|
||||||
onChange := func(filename string, event string) {
|
// onChange := func(filename string, event string) {
|
||||||
if !isWaitingRun {
|
// if !isWaitingRun {
|
||||||
_, _ = os.Stdout.WriteString("\x1b[3;J\x1b[H\x1b[2J")
|
// _, _ = os.Stdout.WriteString("\x1b[3;J\x1b[H\x1b[2J")
|
||||||
isWaitingRun = true
|
// isWaitingRun = true
|
||||||
go func() {
|
// go func() {
|
||||||
time.Sleep(time.Millisecond * 10)
|
// time.Sleep(time.Millisecond * 10)
|
||||||
isWaitingRun = false
|
// isWaitingRun = false
|
||||||
run()
|
// run()
|
||||||
}()
|
// }()
|
||||||
}
|
// }
|
||||||
fmt.Println(u.BYellow("[changed]"), filename)
|
// fmt.Println(u.BYellow("[changed]"), filename)
|
||||||
}
|
// }
|
||||||
_, _ = os.Stdout.WriteString("\x1b[3;J\x1b[H\x1b[2J")
|
// _, _ = os.Stdout.WriteString("\x1b[3;J\x1b[H\x1b[2J")
|
||||||
watchStartPath := filepath.Dir(file)
|
// watchStartPath := filepath.Dir(file)
|
||||||
fmt.Println(u.BMagenta("[watching root path]"), watchStartPath)
|
// fmt.Println(u.BMagenta("[watching root path]"), watchStartPath)
|
||||||
watchDirs := []string{watchStartPath}
|
// watchDirs := []string{watchStartPath}
|
||||||
watchTypes := []string{"js", "json", "yml"}
|
// watchTypes := []string{"js", "json", "yml"}
|
||||||
if extDirs != nil {
|
// if extDirs != nil {
|
||||||
for _, v := range extDirs {
|
// for _, v := range extDirs {
|
||||||
watchDirs = append(watchDirs, v)
|
// watchDirs = append(watchDirs, v)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if extTypes != nil {
|
// if extTypes != nil {
|
||||||
for _, v := range extTypes {
|
// for _, v := range extTypes {
|
||||||
watchTypes = append(watchTypes, v)
|
// watchTypes = append(watchTypes, v)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if w, err := watcher.Start(watchDirs, watchTypes, onChange); err == nil {
|
// if w, err := watcher.Start(watchDirs, watchTypes, onChange); err == nil {
|
||||||
wr.w = w
|
// wr.w = w
|
||||||
go func() {
|
// go func() {
|
||||||
run()
|
// run()
|
||||||
}()
|
// }()
|
||||||
return wr, nil
|
// return wr, nil
|
||||||
} else {
|
// } else {
|
||||||
return nil, err
|
// return nil, err
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExportForDev() string {
|
func ExportForDev() string {
|
||||||
|
Loading…
Reference in New Issue
Block a user