From b93d6ef55149d78d5cc61e06a85b0933d4296d00 Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Fri, 27 May 2022 20:40:25 -0400 Subject: [PATCH] refactor!: use userdata for job object instead of table this might or might not bring lower ram usage there is now only 1 single reference to a lua job object since it's stored in the job struct breaking change since methods need to be called with a colon instead of dot --- job.go | 144 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 113 insertions(+), 31 deletions(-) diff --git a/job.go b/job.go index 5ffb61f..b84f261 100644 --- a/job.go +++ b/job.go @@ -3,6 +3,7 @@ package main import ( "bytes" "errors" + "fmt" "io" "os" "os/exec" @@ -15,6 +16,7 @@ import ( ) var jobs *jobHandler +var jobMetaKey = rt.StringValue("hshjob") type job struct { cmd string @@ -32,6 +34,7 @@ type job struct { cmderr io.Writer stdout *bytes.Buffer stderr *bytes.Buffer + ud *rt.UserData } func (j *job) start() error { @@ -64,7 +67,7 @@ func (j *job) start() error { j.pid = proc.Pid j.running = true - hooks.Em.Emit("job.start", j.lua()) + hooks.Em.Emit("job.start", rt.UserDataValue(j.ud)) return err } @@ -79,7 +82,7 @@ func (j *job) stop() { func (j *job) finish() { j.running = false - hooks.Em.Emit("job.done", j.lua()) + hooks.Em.Emit("job.done", j.ud) } func (j *job) wait() { @@ -107,28 +110,16 @@ func (j *job) getProc() *os.Process { return nil } -func (j *job) lua() rt.Value { - jobFuncs := map[string]util.LuaExport{ - "stop": {j.luaStop, 0, false}, - "start": {j.luaStart, 0, false}, - "foreground": {j.luaForeground, 0, false}, - "background": {j.luaBackground, 0, false}, +func luaStartJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err } - luaJob := rt.NewTable() - util.SetExports(l, luaJob, jobFuncs) - luaJob.Set(rt.StringValue("cmd"), rt.StringValue(j.cmd)) - luaJob.Set(rt.StringValue("running"), rt.BoolValue(j.running)) - luaJob.Set(rt.StringValue("id"), rt.IntValue(int64(j.id))) - luaJob.Set(rt.StringValue("pid"), rt.IntValue(int64(j.pid))) - luaJob.Set(rt.StringValue("exitCode"), rt.IntValue(int64(j.exitCode))) - luaJob.Set(rt.StringValue("stdout"), rt.StringValue(string(j.stdout.Bytes()))) - luaJob.Set(rt.StringValue("stderr"), rt.StringValue(string(j.stderr.Bytes()))) + j, err := jobArg(c, 0) + if err != nil { + return nil, err + } - return rt.TableValue(luaJob) -} - -func (j *job) luaStart(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if !j.running { err := j.start() exit := handleExecErr(err) @@ -139,7 +130,16 @@ func (j *job) luaStart(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } -func (j *job) luaStop(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { +func luaStopJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + + j, err := jobArg(c, 0) + if err != nil { + return nil, err + } + if j.running { j.stop() j.finish() @@ -148,7 +148,16 @@ func (j *job) luaStop(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } -func (j *job) luaForeground(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { +func luaForegroundJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + + j, err := jobArg(c, 0) + if err != nil { + return nil, err + } + if !j.running { return nil, errors.New("job not running") } @@ -157,7 +166,7 @@ func (j *job) luaForeground(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { jobs.foreground = true // this is kinda funny // background continues the process incase it got suspended - err := j.background() + err = j.background() if err != nil { return nil, err } @@ -171,12 +180,21 @@ func (j *job) luaForeground(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } -func (j *job) luaBackground(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { +func luaBackgroundJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.Check1Arg(); err != nil { + return nil, err + } + + j, err := jobArg(c, 0) + if err != nil { + return nil, err + } + if !j.running { return nil, errors.New("job not running") } - err := j.background() + err = j.background() if err != nil { return nil, err } @@ -215,8 +233,10 @@ func (j *jobHandler) add(cmd string, args []string, path string) *job { stdout: &bytes.Buffer{}, stderr: &bytes.Buffer{}, } + jb.ud = jobUserData(jb) + j.jobs[j.latestID] = jb - hooks.Em.Emit("job.add", jb.lua()) + hooks.Em.Emit("job.add", rt.UserDataValue(jb.ud)) return jb } @@ -257,6 +277,44 @@ func (j *jobHandler) stopAll() { } func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table { + jobMethods := rt.NewTable() + jFuncs := map[string]util.LuaExport{ + "stop": {luaStopJob, 1, false}, + "start": {luaStartJob, 1, false}, + "foreground": {luaForegroundJob, 1, false}, + "background": {luaBackgroundJob, 1, false}, + } + util.SetExports(l, jobMethods, jFuncs) + + jobMeta := rt.NewTable() + jobIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + j, _ := jobArg(c, 0) + + arg := c.Arg(1) + val := jobMethods.Get(arg) + + if val != rt.NilValue { + return c.PushingNext1(t.Runtime, val), nil + } + + keyStr, _ := arg.TryString() + + switch keyStr { + case "cmd": val = rt.StringValue(j.cmd) + case "running": val = rt.BoolValue(j.running) + case "id": val = rt.IntValue(int64(j.id)) + case "pid": val = rt.IntValue(int64(j.pid)) + case "exitCode": val = rt.IntValue(int64(j.exitCode)) + case "stdout": val = rt.StringValue(string(j.stdout.Bytes())) + case "stderr": val = rt.StringValue(string(j.stderr.Bytes())) + } + + return c.PushingNext1(t.Runtime, val), nil + } + + jobMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(jobIndex, "__index", 2, false))) + l.SetRegistry(jobMetaKey, rt.TableValue(jobMeta)) + jobFuncs := map[string]util.LuaExport{ "all": {j.luaAllJobs, 0, false}, "last": {j.luaLastJob, 0, false}, @@ -271,6 +329,30 @@ func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table { return luaJob } +func jobArg(c *rt.GoCont, arg int) (*job, error) { + j, ok := valueToJob(c.Arg(arg)) + if !ok { + return nil, fmt.Errorf("#%d must be a job", arg + 1) + } + + return j, nil +} + +func valueToJob(val rt.Value) (*job, bool) { + u, ok := val.TryUserData() + if !ok { + return nil, false + } + + j, ok := u.Value().(*job) + return j, ok +} + +func jobUserData(j *job) *rt.UserData { + jobMeta := l.Registry(jobMetaKey) + return rt.NewUserData(j, jobMeta.AsTable()) +} + func (j *jobHandler) luaGetJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { j.mu.RLock() defer j.mu.RUnlock() @@ -288,7 +370,7 @@ func (j *jobHandler) luaGetJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } - return c.PushingNext1(t.Runtime, job.lua()), nil + return c.PushingNext(t.Runtime, rt.UserDataValue(job.ud)), nil } func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { @@ -317,7 +399,7 @@ func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { jb := j.add(cmd, args, execPath) - return c.PushingNext1(t.Runtime, jb.lua()), nil + return c.PushingNext1(t.Runtime, rt.UserDataValue(jb.ud)), nil } func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { @@ -326,7 +408,7 @@ func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { jobTbl := rt.NewTable() for id, job := range j.jobs { - jobTbl.Set(rt.IntValue(int64(id)), job.lua()) + jobTbl.Set(rt.IntValue(int64(id)), rt.UserDataValue(job.ud)) } return c.PushingNext1(t.Runtime, rt.TableValue(jobTbl)), nil @@ -358,5 +440,5 @@ func (j *jobHandler) luaLastJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } - return c.PushingNext1(t.Runtime, job.lua()), nil + return c.PushingNext1(t.Runtime, rt.UserDataValue(job.ud)), nil }