{"id":17219487,"url":"https://github.com/kelindar/lua","last_synced_at":"2025-04-13T22:35:02.406Z","repository":{"id":57509678,"uuid":"236343485","full_name":"kelindar/lua","owner":"kelindar","description":"Wrapper around LUA script executor for long-running scripts","archived":false,"fork":false,"pushed_at":"2024-09-05T12:12:46.000Z","size":61,"stargazers_count":18,"open_issues_count":1,"forks_count":7,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-27T12:52:30.374Z","etag":null,"topics":["lua","script-engine","scripting"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kelindar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["kelindar"]}},"created_at":"2020-01-26T16:53:56.000Z","updated_at":"2024-10-17T16:36:42.000Z","dependencies_parsed_at":"2023-02-18T06:40:18.847Z","dependency_job_id":"6a0b09d0-9409-4ee7-99a8-d689d2d09147","html_url":"https://github.com/kelindar/lua","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelindar%2Flua","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelindar%2Flua/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelindar%2Flua/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelindar%2Flua/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kelindar","download_url":"https://codeload.github.com/kelindar/lua/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248791256,"owners_count":21162174,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lua","script-engine","scripting"],"created_at":"2024-10-15T03:49:58.821Z","updated_at":"2025-04-13T22:35:02.318Z","avatar_url":"https://github.com/kelindar.png","language":"Go","readme":"# Concurrent LUA Executor\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/kelindar/lua)](https://goreportcard.com/report/github.com/kelindar/lua)\n[![GoDoc](https://godoc.org/github.com/kelindar/lua?status.svg)](https://godoc.org/github.com/kelindar/lua)\n\nThis repository contains a concurrent LUA executor that is designed to keep running a same (but updateable) set of scripts over a long period of time. The design of the library is quite opinionated, as it requires the `main()` function to be present in the script in order to run it. It also maintains a pool of VMs per `Script` instance to increase throughput per script.\n\nUnder the hood, it uses [gopher-lua](https://github.com/yuin/gopher-lua) library but abstracts it away, in order to be easily replaced in future if required. \n\n\n## Usage Example\nBelow is the usage example which runs the fibonacci LUA script with input `10`.\n\n```go\n// Load the script\ns, err := FromString(\"test.lua\", `\n    function main(n)\n        if n \u003c 2 then return 1 end\n        return main(n - 2) + main(n - 1)\n    end\n`)\n\n// Run the main() function with 10 as argument\nresult, err := s.Run(context.Background(), 10)\nprintln(result.String()) // Output: 89\n```\n\nThe library also supports passing complex data types, thanks to [gopher-luar](https://github.com/layeh/gopher-luar). In the example below we create a `Person` struct and update its name in LUA as a side-effect of the script. It also returns the updated name back as a string.\n\n```go\n// Load the script\ns, err := FromString(\"test.lua\", `\n    function main(input)\n        input.Name = \"Updated\"\n        return input.Name\n    end\n`)\n\ninput := \u0026Person{ Name: \"Roman\" }\nout, err := s.Run(context.Background(), input)\nprintln(out)         // Outputs: \"Updated\"\nprintln(input.Name)  // Outputs: \"Updated\"\n```\n\n## Native Modules\n\nThis library also supports and abstracts modules, which allows you to provide one or multiple native libraries which can be used by the script. These things are just ensembles of functions which are implemented in pure Go. \n\nSuch functions must comply to a specific interface - they should have their arguments as the library's values (e.g. `Number`, `String` or `Bool`) and the result can be either a value and `error` or just an `error`. Here's an example of such function:\n```go\nfunc hash(s lua.String) (lua.Number, error) {\n\th := fnv.New32a()\n\th.Write([]byte(s))\n\n\treturn lua.Number(h.Sum32()), nil\n}\n```\n\nIn order to use it, the functions should be registered into a `NativeModule` which then is loaded when script is created.\n```go\n// Create a test module which provides hash function\nmodule := \u0026NativeModule{\n    Name:    \"test\",\n    Version: \"1.0.0\",\n}\nmodule.Register(\"hash\", hash)\n\n// Load the script\ns, err := FromString(\"test.lua\", `\n    local api = require(\"test\")\n\n    function main(input)\n        return api.hash(input)\n    end\n`, module) // \u003c- attach the module\n\nout, err := s.Run(context.Background(), \"abcdef\")\nprintln(out) // Output: 4282878506\n\n```\n\n## Script Modules \n\nSimilarly to native modules, the library also supports LUA script modules. In order to use it, first you need to create a script which contains a module and returns a table with the functions. Then, create a `ScriptModule` which points to the script with `Name` which can be used in the `require` statement.\n\n```go\nmoduleCode, err := FromString(\"module.lua\", `\n    local demo_mod = {} -- The main table\n\n    function demo_mod.Mult(a, b)\n        return a * b\n    end\n\n    return demo_mod\n`)\n\n// Create a test module which provides hash function\nmodule := \u0026ScriptModule{\n    Script:  moduleCode,\n    Name:    \"demo_mod\",\n    Version: \"1.0.0\",\n}\n```\n\nFinally, attach the module to the script as with native modules.\n\n```go\n// Load the script\ns, err := FromString(\"test.lua\", `\n    local demo = require(\"demo_mod\")\n\n    function main(input)\n        return demo.Mult(5, 5)\n    end\n`, module) // \u003c- attach the module\n\nout, err := s.Run(context.Background())\nprintln(out) // Output: 25\n```\n\n\n## Benchmarks\n\n```\nBenchmark_Serial/fib-8         \t 5870025\t       203 ns/op\t      16 B/op\t       2 allocs/op\nBenchmark_Serial/empty-8       \t 8592448\t       137 ns/op\t       0 B/op\t       0 allocs/op\nBenchmark_Serial/update-8      \t 1000000\t      1069 ns/op\t     224 B/op\t      14 allocs/op\n```\n","funding_links":["https://github.com/sponsors/kelindar"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkelindar%2Flua","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkelindar%2Flua","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkelindar%2Flua/lists"}