diff --git a/api/http.go b/api/http.go index 0aff9ccc..8482cdd3 100644 --- a/api/http.go +++ b/api/http.go @@ -14,6 +14,7 @@ import ( "github.com/yaoapp/gou/process" "github.com/yaoapp/gou/session" "github.com/yaoapp/gou/types" + "github.com/yaoapp/kun/exception" "github.com/yaoapp/kun/maps" ) @@ -55,26 +56,35 @@ func ProcessGuard(name string) gin.HandlerFunc { process, err := process.Of(name, args...) if err != nil { - c.JSON(400, gin.H{"code": 400, "message": fmt.Sprintf("Guard: %s %s", name, err.Error())}) + c.JSON(500, gin.H{"code": 500, "message": "Guard process error: " + err.Error()}) c.Abort() return } - if sid, has := c.Get("__sid"); has { // 设定会话ID + if sid, has := c.Get("__sid"); has { // Set session id if sid, ok := sid.(string); ok { process.WithSID(sid) } } - if global, has := c.Get("__global"); has { // 设定全局变量 + if global, has := c.Get("__global"); has { // Set global variables if global, ok := global.(map[string]interface{}); ok { process.WithGlobal(global) } } - v := process.Run() + err = process.Execute() + if err != nil { + ex := exception.New(err.Error(), 500) + c.JSON(ex.Code, gin.H{"code": ex.Code, "message": ex.Message}) + c.Abort() + return + } + defer process.Release() + + v := process.Value() if data, ok := v.(map[string]interface{}); ok { - if sid, ok := data["__sid"].(string); ok { + if sid, ok := data["sid"].(string); ok { c.Set("__sid", sid) } diff --git a/connector/connector.go b/connector/connector.go index 02bcd167..930dc07f 100644 --- a/connector/connector.go +++ b/connector/connector.go @@ -5,6 +5,7 @@ import ( "github.com/yaoapp/gou/application" "github.com/yaoapp/gou/connector/database" + "github.com/yaoapp/gou/connector/moapi" mongo "github.com/yaoapp/gou/connector/mongo" "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/gou/connector/redis" @@ -41,6 +42,17 @@ func Load(file string, id string) (Connector, error) { return Connectors[id], nil } +// New create a new connector +func New(typ string, id string, data []byte) (Connector, error) { + c, err := make(typ) + if err != nil { + return nil, err + } + c.Register(id, "__source__", data) + Connectors[id] = c + return Connectors[id], nil +} + // Select a connector func Select(id string) (Connector, error) { connector, has := Connectors[id] @@ -82,6 +94,10 @@ func make(typ string) (Connector, error) { case OPENAI: c := &openai.Connector{} return c, nil + + case MOAPI: + c := &moapi.Connector{} + return c, nil } return nil, fmt.Errorf("%s does not support yet", typ) diff --git a/connector/moapi/moapi.go b/connector/moapi/moapi.go new file mode 100644 index 00000000..45e99b49 --- /dev/null +++ b/connector/moapi/moapi.go @@ -0,0 +1,78 @@ +package moapi + +import ( + "github.com/yaoapp/gou/application" + "github.com/yaoapp/gou/helper" + "github.com/yaoapp/xun/dbal/query" + "github.com/yaoapp/xun/dbal/schema" +) + +// Connector connector +type Connector struct { + id string + file string + Name string `json:"name"` + Options Options `json:"options"` +} + +// Options the redis connector option +type Options struct { + Proxy string `json:"proxy,omitempty"` + Model string `json:"model,omitempty"` + Key string `json:"key"` +} + +// Register the connections from dsl +func (o *Connector) Register(file string, id string, dsl []byte) error { + o.id = id + o.file = file + err := application.Parse(file, dsl, o) + if err != nil { + return err + } + + o.Options.Proxy = helper.EnvString(o.Options.Proxy) + o.Options.Model = helper.EnvString(o.Options.Model) + o.Options.Key = helper.EnvString(o.Options.Key) + return nil +} + +// Is the connections from dsl +func (o *Connector) Is(typ int) bool { + return 6 == typ || 8 == typ +} + +// ID get connector id +func (o *Connector) ID() string { + return o.id +} + +// Query get connector query interface +func (o *Connector) Query() (query.Query, error) { + return nil, nil +} + +// Schema get connector schema interface +func (o *Connector) Schema() (schema.Schema, error) { + return nil, nil +} + +// Close connections +func (o *Connector) Close() error { + return nil +} + +// Setting get the connection setting +func (o *Connector) Setting() map[string]interface{} { + + host := "https://api.moapi.ai" + if o.Options.Proxy != "" { + host = o.Options.Proxy + } + + return map[string]interface{}{ + "host": host, + "key": o.Options.Key, + "model": o.Options.Model, + } +} diff --git a/connector/types.go b/connector/types.go index 54da07fa..33c865e9 100644 --- a/connector/types.go +++ b/connector/types.go @@ -27,6 +27,9 @@ const ( // WEAVIATE the weaviate connector WEAVIATE + // MOAPI the moapi connector + MOAPI + // SCRIPT ? the script connector ( difference with widget ?) SCRIPT ) @@ -45,6 +48,7 @@ var types = map[string]int{ "openai": OPENAI, "weaviate": WEAVIATE, "script": SCRIPT, // ? + "moapi": MOAPI, } // Connector the connector interface diff --git a/process/process.go b/process/process.go index bfa6a641..30984b20 100644 --- a/process/process.go +++ b/process/process.go @@ -6,6 +6,8 @@ import ( "strings" "time" + "github.com/fatih/color" + jsoniter "github.com/json-iterator/go" "github.com/yaoapp/kun/exception" ) @@ -57,7 +59,13 @@ func (process *Process) Execute() (err error) { done := make(chan struct{}) go func() { defer close(done) - defer func() { err = exception.Catch(recover()) }() + defer func() { + recovered := recover() + err = exception.Catch(recovered) + if err != nil { + exception.DebugPrint(err, "%s", process) + } + }() value := hd(process) process._val = &value }() @@ -195,6 +203,22 @@ func (process *Process) WithRuntime(runtime Runtime) *Process { return process } +// String the process as string +func (process Process) String() string { + args, _ := jsoniter.MarshalToString(process.Args) + global, _ := jsoniter.MarshalToString(process.Global) + return fmt.Sprintf("%s%s\n%s%s\n%s%s\n%s%s\n", + color.YellowString("Process: "), + color.WhiteString(process.Name), + color.YellowString("Sid: "), + color.WhiteString(process.Sid), + color.YellowString("Args: \n"), + color.WhiteString(args), + color.YellowString("Global: \n"), + color.WhiteString(global), + ) +} + // handler get the process handler func (process *Process) handler() (Handler, error) { if hander, has := Handlers[process.Handler]; has && hander != nil { diff --git a/runtime/v8/context.go b/runtime/v8/context.go index 576fe3f0..f845c573 100644 --- a/runtime/v8/context.go +++ b/runtime/v8/context.go @@ -3,7 +3,6 @@ package v8 import ( "context" - "github.com/fatih/color" "github.com/yaoapp/gou/runtime/v8/bridge" "github.com/yaoapp/gou/runtime/v8/objects/console" "github.com/yaoapp/kun/log" @@ -45,7 +44,7 @@ func (context *Context) Call(method string, args ...interface{}) (interface{}, e jsRes, err := global.MethodCall(method, bridge.Valuers(jsArgs)...) if err != nil { if e, ok := err.(*v8go.JSError); ok { - color.Red("%s\n\n", StackTrace(e, context.SourceRoots)) + PrintException(method, args, e, context.SourceRoots) } log.Error("%s.%s %s", context.ID, method, err.Error()) return nil, err @@ -111,7 +110,7 @@ func (context *Context) CallWith(ctx context.Context, method string, args ...int jsRes, err := global.MethodCall(method, bridge.Valuers(jsArgs)...) if err != nil { if e, ok := err.(*v8go.JSError); ok { - color.Red("%s\n\n", StackTrace(e, context.SourceRoots)) + PrintException(method, args, e, context.SourceRoots) } errChan <- err return diff --git a/runtime/v8/runner.go b/runtime/v8/runner.go index f2742e1d..db22a5f4 100644 --- a/runtime/v8/runner.go +++ b/runtime/v8/runner.go @@ -5,7 +5,6 @@ import ( "strings" "time" - "github.com/fatih/color" "github.com/google/uuid" "github.com/yaoapp/gou/runtime/v8/bridge" "github.com/yaoapp/gou/runtime/v8/objects/console" @@ -230,7 +229,7 @@ func (runner *Runner) _exec() { jsRes, err := global.MethodCall(runner.method, bridge.Valuers(jsArgs)...) if err != nil { if e, ok := err.(*v8go.JSError); ok { - color.Red("%s\n\n", StackTrace(e, runner.script.SourceRoots)) + PrintException(runner.method, runner.args, e, runner.script.SourceRoots) } runner.chResp <- err return diff --git a/runtime/v8/script.go b/runtime/v8/script.go index 56dbb26b..2d942dda 100644 --- a/runtime/v8/script.go +++ b/runtime/v8/script.go @@ -10,7 +10,6 @@ import ( "time" "github.com/evanw/esbuild/pkg/api" - "github.com/fatih/color" "github.com/yaoapp/gou/application" "github.com/yaoapp/gou/process" "github.com/yaoapp/gou/runtime/v8/bridge" @@ -658,7 +657,7 @@ func (script *Script) execStandard(process *process.Process) interface{} { // Debug output the error stack if e, ok := err.(*v8go.JSError); ok { - color.Red("%s\n\n", StackTrace(e, script.SourceRoots)) + PrintException(process.Method, process.Args, e, script.SourceRoots) } log.Error("scripts.%s.%s %s", script.ID, process.Method, err.Error()) diff --git a/runtime/v8/sourcemap.go b/runtime/v8/sourcemap.go index 0273ecb7..4c5eacb5 100644 --- a/runtime/v8/sourcemap.go +++ b/runtime/v8/sourcemap.go @@ -7,9 +7,11 @@ import ( "strconv" "strings" + "github.com/fatih/color" "github.com/go-sourcemap/sourcemap" jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou/application" + "github.com/yaoapp/kun/exception" "rogchap.com/v8go" ) @@ -65,13 +67,27 @@ func clearSourceMaps() { SourceCodes = map[string][]byte{} } +// PrintException print the exception +func PrintException(method string, args []interface{}, jserr *v8go.JSError, rootMapping interface{}) { + + if runtimeOption.Debug { + ex := exception.New(jserr.Message, 500) + color.Red("\n----------------------------------") + color.Red("Script Exception: %s", fmt.Sprintf("%d %s", ex.Code, ex.Message)) + color.Red("----------------------------------") + + color.Red("%s\n", StackTrace(jserr, rootMapping)) + fmt.Println(color.YellowString("\nMethod:"), color.WhiteString("%s", method)) + color.Yellow("Args:") + raw, _ := jsoniter.MarshalToString(args) + color.White("%s\n", raw) + } +} + // StackTrace get the stack trace func StackTrace(jserr *v8go.JSError, rootMapping interface{}) string { - // Production mode will not show the stack trace - if runtimeOption.Debug == false { - return jserr.Message - } + ex := exception.New(jserr.Message, 500) // Development mode will show the stack trace entries := parseStackTrace(jserr.StackTrace) @@ -84,7 +100,7 @@ func StackTrace(jserr *v8go.JSError, rootMapping interface{}) string { return err.Error() + "\n" + jserr.StackTrace } - return fmt.Sprintf("%s\n%s", jserr.Message, output) + return fmt.Sprintf("%s\n%s", fmt.Sprintf("%d %s", ex.Code, ex.Message), output) } func (entry *StackLogEntry) String() string { diff --git a/runtime/v8/sourcemap_test.go b/runtime/v8/sourcemap_test.go index 0ef0f2ca..036bb37b 100644 --- a/runtime/v8/sourcemap_test.go +++ b/runtime/v8/sourcemap_test.go @@ -64,7 +64,7 @@ func TestStackTrace(t *testing.T) { trace := StackTrace(e, nil) assert.NotEmpty(t, trace) - assert.Contains(t, trace, "Exception|400: Error occurred") + assert.Contains(t, trace, "400 Error occurred") assert.Contains(t, trace, "/scripts/runtime/ts/page.ts:12:2") assert.Contains(t, trace, "/scripts/runtime/ts/lib/bar.ts:7:2") assert.Contains(t, trace, "/scripts/runtime/ts/lib/err.ts:8:10") @@ -72,7 +72,7 @@ func TestStackTrace(t *testing.T) { // with source root trace = StackTrace(e, map[string]string{"/scripts": "/iscripts"}) assert.NotEmpty(t, trace) - assert.Contains(t, trace, "Exception|400: Error occurred") + assert.Contains(t, trace, "400 Error occurred") assert.Contains(t, trace, "/iscripts/runtime/ts/page.ts:12:2") assert.Contains(t, trace, "/iscripts/runtime/ts/lib/bar.ts:7:2") assert.Contains(t, trace, "/iscripts/runtime/ts/lib/err.ts:8:10") @@ -87,7 +87,7 @@ func TestStackTrace(t *testing.T) { trace = StackTrace(e, replace) assert.NotEmpty(t, trace) - assert.Contains(t, trace, "Exception|400: Error occurred") + assert.Contains(t, trace, "400 Error occurred") assert.Contains(t, trace, "/fscripts/runtime/ts/page.ts:12:2") assert.Contains(t, trace, "/fscripts/runtime/ts/lib/bar.ts:7:2") assert.Contains(t, trace, "/fscripts/runtime/ts/lib/err.ts:8:10")