2023-07-16 00:03:55 +00:00
|
|
|
package fs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/rjeczalik/notify"
|
|
|
|
rt "github.com/arnodel/golua/runtime"
|
|
|
|
)
|
|
|
|
|
2024-12-22 16:39:15 +00:00
|
|
|
// #type
|
|
|
|
// Watcher type describes a `fs` library file watcher.
|
|
|
|
type watcher struct{
|
2023-07-16 00:03:55 +00:00
|
|
|
path string
|
|
|
|
callback *rt.Closure
|
|
|
|
paused bool
|
|
|
|
started bool
|
|
|
|
ud *rt.UserData
|
|
|
|
notifyChan chan notify.EventInfo
|
|
|
|
}
|
|
|
|
|
2024-12-22 16:39:15 +00:00
|
|
|
func (w *watcher) start() {
|
2023-07-16 00:03:55 +00:00
|
|
|
if w.callback == nil || w.started {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
w.started = true
|
|
|
|
w.notifyChan = make(chan notify.EventInfo)
|
|
|
|
notify.Watch(w.path, w.notifyChan, notify.All)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
for notif := range w.notifyChan {
|
|
|
|
ev := notif.Event().String()
|
|
|
|
path := notif.Path()
|
|
|
|
|
|
|
|
_, err := rt.Call1(rtmm.MainThread(), rt.FunctionValue(w.callback), rt.StringValue(ev), rt.StringValue(path))
|
|
|
|
if err != nil {
|
|
|
|
// TODO: throw error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2024-12-22 16:39:15 +00:00
|
|
|
func (w *watcher) stop() {
|
2023-07-16 00:03:55 +00:00
|
|
|
w.started = false
|
|
|
|
notify.Stop(w.notifyChan)
|
|
|
|
}
|
|
|
|
|
2024-12-22 16:39:15 +00:00
|
|
|
// #member
|
|
|
|
// start()
|
|
|
|
// Start/resume file watching.
|
2023-07-16 00:03:55 +00:00
|
|
|
func watcherStart(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|
|
|
pw, err := watcherArg(c, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
pw.start()
|
|
|
|
|
|
|
|
return c.Next(), nil
|
|
|
|
}
|
|
|
|
|
2024-12-22 16:39:15 +00:00
|
|
|
// #member
|
|
|
|
// stop()
|
|
|
|
// Stops watching for changes. Effectively ignores changes.
|
2023-07-16 00:03:55 +00:00
|
|
|
func watcherStop(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|
|
|
pw, err := watcherArg(c, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
pw.stop()
|
|
|
|
|
|
|
|
return c.Next(), nil
|
|
|
|
}
|
|
|
|
|
2024-12-22 16:39:15 +00:00
|
|
|
func newWatcher(path string, callback *rt.Closure) *watcher {
|
|
|
|
pw := &watcher{
|
2023-07-16 00:03:55 +00:00
|
|
|
path: path,
|
|
|
|
callback: callback,
|
|
|
|
}
|
|
|
|
pw.ud = watcherUserData(pw)
|
|
|
|
pw.start()
|
|
|
|
|
|
|
|
return pw
|
|
|
|
}
|
|
|
|
|
2024-12-22 16:39:15 +00:00
|
|
|
func watcherArg(c *rt.GoCont, arg int) (*watcher, error) {
|
2023-07-16 00:03:55 +00:00
|
|
|
j, ok := valueToWatcher(c.Arg(arg))
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("#%d must be a watcher", arg + 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
return j, nil
|
|
|
|
}
|
|
|
|
|
2024-12-22 16:39:15 +00:00
|
|
|
func valueToWatcher(val rt.Value) (*watcher, bool) {
|
2023-07-16 00:03:55 +00:00
|
|
|
u, ok := val.TryUserData()
|
|
|
|
if !ok {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
2024-12-22 16:39:15 +00:00
|
|
|
j, ok := u.Value().(*watcher)
|
2023-07-16 00:03:55 +00:00
|
|
|
return j, ok
|
|
|
|
}
|
|
|
|
|
2024-12-22 16:39:15 +00:00
|
|
|
func watcherUserData(j *watcher) *rt.UserData {
|
2023-07-16 00:03:55 +00:00
|
|
|
watcherMeta := rtmm.Registry(watcherMetaKey)
|
|
|
|
return rt.NewUserData(j, watcherMeta.AsTable())
|
|
|
|
}
|