Skip to content

Commit

Permalink
dev: run app stack first step
Browse files Browse the repository at this point in the history
  • Loading branch information
wwhai committed Mar 6, 2023
1 parent e7d1a26 commit cf0bfea
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 13 deletions.
197 changes: 197 additions & 0 deletions appstack/appstack_runner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package appstack

import (
"context"
"fmt"
"os"

"github.com/i4de/rulex/glogger"
"github.com/i4de/rulex/typex"
lua "github.com/yuin/gopher-lua"
)

// lua 虚拟机的参数
const _VM_Registry_Size int = 1024 * 1024 // 默认堆栈大小
const _VM_Registry_MaxSize int = 1024 * 1024 // 默认最大堆栈
const _VM_Registry_GrowStep int = 32 // 默认CPU消耗

/*
*
* 轻量级应用
*
*/
type Application struct {
UUID string `json:"uuid"` // 名称
Name string `json:"name"` // 名称
Version string `json:"version"` // 版本号
Filepath string `json:"filepath"` // 文件路径, 是相对于main的apps目录
luaMainFunc *lua.LFunction `json:"-"`
vm *lua.LState `json:"-"` // lua 环境
ctx context.Context `json:"-"`
cancel context.CancelFunc `json:"-"`
}

func NewApplication(uuid, Name, Version, Filepath string) *Application {
app := new(Application)
app.Name = Name
app.Version = Version
app.Filepath = Filepath
app.vm = lua.NewState(lua.Options{
RegistrySize: _VM_Registry_Size,
RegistryMaxSize: _VM_Registry_MaxSize,
RegistryGrowStep: _VM_Registry_GrowStep,
})
return app
}

/*
*
* 管理器
*
*/
type AppStack struct {
Applications map[string]*Application
}

func NewAppStack() *AppStack {
as := new(AppStack)
as.Applications = map[string]*Application{}
return as
}

/*
*
* 加载本地文件到lua虚拟机
*
*/
func (as *AppStack) LoadApp(app *Application) error {

// 临时校验语法
tempVm := lua.NewState()
bytes, err := os.ReadFile("./apps/" + app.Filepath)
if err != nil {
return err
}
if err := tempVm.DoString(string(bytes)); err != nil {
return err
}
// 检查名称
AppNAME := tempVm.GetGlobal("AppNAME")
if AppNAME == nil {
return fmt.Errorf("'AppNAME' field not exists")
}
if AppNAME.Type() != lua.LTString {
return fmt.Errorf("'AppNAME' must be string")
}
// 检查类型
AppVERSION := tempVm.GetGlobal("AppVERSION")
if AppVERSION == nil {
return fmt.Errorf("'AppVERSION' field not exists")
}
if AppVERSION.Type() != lua.LTString {
return fmt.Errorf("'AppVERSION' must be string")
}
// 检查描述信息
AppDESCRIPTION := tempVm.GetGlobal("AppDESCRIPTION")
if AppDESCRIPTION == nil {
if AppDESCRIPTION.Type() != lua.LTString {
return fmt.Errorf("'AppDESCRIPTION' must be string")
}
}

// 检查函数入口
AppMain := tempVm.GetGlobal("Main")
if AppMain == nil {
return fmt.Errorf("'Main' field not exists")
}
if AppMain.Type() != lua.LTFunction {
return fmt.Errorf("'Main' must be function(arg)")
}

// 加载到内存里
fMain := *AppMain.(*lua.LFunction)
app.luaMainFunc = &fMain
if err := as.startApp(app); err != nil {
return err
}
as.Applications[app.UUID] = app
//
tempVm.Close()
tempVm = nil
return nil
}

/*
*
* 启动 function Main(args) --do-some-thing-- return 0 end
*
*/
func (as *AppStack) startApp(app *Application) error {
// args := lua.LBool(false) // Main的参数,未来准备扩展
ctx, cancel := context.WithCancel(typex.GCTX)
app.ctx = ctx
app.cancel = cancel
go func(ctx context.Context) {
app.vm.SetContext(ctx)
err := app.vm.CallByParam(lua.P{
Fn: app.luaMainFunc, // 回调函数
NRet: 1, // 一个返回值
Protect: true, // 受保护
})
if err != nil {
glogger.GLogger.Error("startApp error:", err)
return
}
}(app.ctx)

return nil
}

/*
*
* 删除APP
*
*/
func (as *AppStack) RemoveApp(uuid string) error {
if app, ok := as.Applications[uuid]; ok {
app.cancel()
app.vm.Close()
delete(as.Applications, uuid)
app.vm = nil
}
return nil
}

/*
*
* 更新应用信息
*
*/
func (as *AppStack) UpdateApp(app *Application) error {
if _, ok := as.Applications[app.UUID]; ok {
as.Applications[app.UUID] = app
}
return fmt.Errorf("update failed, app not exists:%s", app.UUID)

}

/*
*
* 获取列表
*
*/
func (as *AppStack) ListApp() []Application {
apps := []Application{}
for _, v := range as.Applications {
apps = append(apps, *v)
}
return apps
}

func (as *AppStack) Stop() {
for _, app := range as.Applications {
app.cancel()
app.vm.Close()
app.vm = nil
}
}
7 changes: 5 additions & 2 deletions appstack/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ AppNAME = "test_demo"
-- 版本信息,必须符合 x.y.z 格式
AppVERSION = "1.0.0"
-- 关于这个应用的一些描述信息
AppDESCTIPTION = "A demo app"
AppDESCRIPTION = "A demo app"
-- 必须包含 APPMain(arg) 函数作为 app 启动点
function Main(arg)
while true do
Expand All @@ -32,4 +32,7 @@ function Main(arg)
end
end

```
```

## 内部原理
首先用户在编辑器里面写一段 lua 代码,然后 rulex 会加载这段 lua 代码执行。代码最终被保存在本地。
9 changes: 9 additions & 0 deletions test/apps/helloworld_1.0.0.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
AppNAME = "test_demo"
AppVERSION = "1.0.0"
AppDESCRIPTION = "A demo app"
function Main(arg)
while true do
print("Message From Main:", AppNAME, AppVERSION, AppDESCRIPTION)
end
return 0
end
28 changes: 28 additions & 0 deletions test/appstack_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package test

import (
"testing"
"time"

"github.com/i4de/rulex/appstack"
)

// go test -timeout 30s -run ^Test_appStack github.com/i4de/rulex/test -v -count=1
func Test_appStack(t *testing.T) {
as := appstack.NewAppStack()

err := as.LoadApp(appstack.NewApplication("test-uuid-1", "test-name",
"1.0.1", "helloworld_1.0.0.lua"))
if err != nil {
t.Fatal(err)
}
t.Log(as)
go func() {
for i := 0; i < 1000; i++ {

t.Log("Test_appStack ======>")
}
}()
time.Sleep(30 * time.Second)

}
4 changes: 2 additions & 2 deletions typex/version.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// Warning:
// This file is generated by go compiler, don't change it!!!
// Generated Time: "2023-03-03 19:53:48"
// Generated Time: "2023-03-06 15:41:01"
// Build on: 5.18.17-amd64-desktop-community-hwe
//
package typex
Expand All @@ -13,6 +13,6 @@ type Version struct {

var DefaultVersion = Version{
Version: `v0.4.3`,
ReleaseTime: "2023-03-03 19:53:48",
ReleaseTime: "2023-03-06 15:41:01",
}

10 changes: 2 additions & 8 deletions typex/xpipline.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ import (
)

// RunPipline
// Run lua as pipline
//
// Run lua as pipline
func RunPipline(vm *lua.LState, funcs map[string]*lua.LFunction, arg lua.LValue) (lua.LValue, error) {
// start 1
acc := 1
return pipLine(vm, acc, funcs, arg)
}

//
func pipLine(vm *lua.LState, acc int, funcs map[string]*lua.LFunction, arg lua.LValue) (lua.LValue, error) {
if acc == len(funcs) {
values, err0 := callLuaFunc(vm, funcs[strconv.Itoa(acc)], arg)
Expand Down Expand Up @@ -48,22 +47,17 @@ func pipLine(vm *lua.LState, acc int, funcs map[string]*lua.LFunction, arg lua.L

}

//
// validate lua callback
//
func validate(values []lua.LValue, f func() (lua.LValue, error)) (lua.LValue, error) {
// Lua call back must have 2 args!!!
if len(values) != 2 {
return nil, errors.New("'Action' callback must have 2 arguments:[bool, T]")
return nil, errors.New("'Action' callback must have 2 return value:[bool, T]")
} else {
return f()
}
}

//
//
// 执行lua函数的接口, 后期可以用这个接口来实现运行 lua 微服务
//
func Execute(vm *lua.LState, k string, args ...lua.LValue) (interface{}, error) {
callable := vm.GetGlobal(k)
if callable.Type() == lua.LTFunction {
Expand Down
2 changes: 1 addition & 1 deletion utils/banner.b
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
|
|* Welcome to RULEX framework world <'_'>
|* Version: v0.4.3-d5df539dbd1a97d
|* Build at: 2023-03-03 19:53:48
|* Build at: 2023-03-06 15:41:01
|* Document: https://rulex.pages.dev
|

0 comments on commit cf0bfea

Please sign in to comment.