Merge pull request #727 from trheyi/main
[feat] Add $Backend function call to directly invoke backend functions from frontend scripts.
This commit is contained in:
commit
346a310eb6
5 changed files with 228 additions and 70 deletions
122
data/bindata.go
122
data/bindata.go
File diff suppressed because one or more lines are too long
|
|
@ -31,7 +31,7 @@ func Render(process *process.Process) interface{} {
|
|||
ctx.Request.URL.Path = route
|
||||
r, _, err := NewRequestContext(ctx)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("<div class='text-danger'> %s </div>", err.Error())
|
||||
return fmt.Sprintf("<span class='sui-render-error'> %s </span>", err.Error())
|
||||
}
|
||||
|
||||
var c *core.Cache = nil
|
||||
|
|
@ -42,27 +42,33 @@ func Render(process *process.Process) interface{} {
|
|||
if c == nil {
|
||||
c, _, err = r.MakeCache()
|
||||
if err != nil {
|
||||
return fmt.Sprintf("<div class='text-danger'> %s </div>", err.Error())
|
||||
return fmt.Sprintf("<span class='sui-render-error'> %s </span>", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if c == nil {
|
||||
return fmt.Sprintf("<div class='text-danger'> Cache not found </div>")
|
||||
return fmt.Sprintf("<span class='sui-render-error'> Cache not found </span>")
|
||||
}
|
||||
|
||||
// Guard the page
|
||||
code, err := r.Guard(c)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("<span class='sui-render-error'> %v %s </span>", code, err.Error())
|
||||
}
|
||||
|
||||
data, ok := payload["data"].(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Sprintf("<div class='text-danger'> Data not found </div>")
|
||||
return fmt.Sprintf("<span class='sui-render-error'> Data not found </span>")
|
||||
}
|
||||
|
||||
name, ok := payload["name"].(string)
|
||||
if !ok {
|
||||
return fmt.Sprintf("<div class='text-danger'> Name not found </div>")
|
||||
return fmt.Sprintf("<span class='sui-render-error'> Name not found </span>")
|
||||
}
|
||||
|
||||
html, err := r.renderHTML(c, name, c.HTML, core.Data(data))
|
||||
if err != nil {
|
||||
return fmt.Sprintf("<div class='text-danger'> %s </div>", err.Error())
|
||||
return fmt.Sprintf("<span class='sui-render-error'> %s </span>", err.Error())
|
||||
}
|
||||
|
||||
return html
|
||||
|
|
|
|||
102
sui/api/run.go
102
sui/api/run.go
|
|
@ -1,8 +1,106 @@
|
|||
package api
|
||||
|
||||
import "github.com/yaoapp/gou/process"
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yaoapp/gou/process"
|
||||
"github.com/yaoapp/kun/exception"
|
||||
"github.com/yaoapp/kun/log"
|
||||
"github.com/yaoapp/yao/sui/core"
|
||||
)
|
||||
|
||||
// Run the backend script, with Api prefix method
|
||||
func Run(process *process.Process) interface{} {
|
||||
return nil
|
||||
process.ValidateArgNums(3)
|
||||
ctx, ok := process.Args[0].(*gin.Context)
|
||||
if !ok {
|
||||
exception.New("The context is required", 400).Throw()
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx.Header("Content-Type", "text/html; charset=utf-8")
|
||||
route := process.ArgsString(1)
|
||||
payload := process.ArgsMap(2)
|
||||
if route == "" {
|
||||
exception.New("The route is required", 400).Throw()
|
||||
return nil
|
||||
}
|
||||
|
||||
if payload["method"] == nil {
|
||||
exception.New("The method is required", 400).Throw()
|
||||
return nil
|
||||
}
|
||||
|
||||
method, ok := payload["method"].(string)
|
||||
if !ok {
|
||||
exception.New("The method must be a string", 400).Throw()
|
||||
return nil
|
||||
}
|
||||
|
||||
args := []interface{}{}
|
||||
if payload["args"] != nil {
|
||||
args, ok = payload["args"].([]interface{})
|
||||
if !ok {
|
||||
exception.New("The args must be an array", 400).Throw()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Request.URL.Path = route
|
||||
r, _, err := NewRequestContext(ctx)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
return nil
|
||||
}
|
||||
|
||||
var c *core.Cache = nil
|
||||
if !r.Request.DisableCache() {
|
||||
c = core.GetCache(r.File)
|
||||
}
|
||||
|
||||
if c == nil {
|
||||
c, _, err = r.MakeCache()
|
||||
if err != nil {
|
||||
log.Error("[SUI] Can't make cache, %s %s error: %s", route, method, err.Error())
|
||||
exception.New("Can't make cache, please the route and method is correct, get more information from the log.", 500).Throw()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Guard the page
|
||||
code, err := r.Guard(c)
|
||||
if err != nil {
|
||||
exception.Err(err, code).Throw()
|
||||
return nil
|
||||
}
|
||||
|
||||
if c == nil {
|
||||
exception.New("Cache not found", 500).Throw()
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.Script == nil {
|
||||
exception.New("Script not found", 500).Throw()
|
||||
return nil
|
||||
}
|
||||
|
||||
scriptCtx, err := c.Script.NewContext(process.Sid, nil)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
return nil
|
||||
}
|
||||
defer scriptCtx.Close()
|
||||
|
||||
global := scriptCtx.Global()
|
||||
if !global.Has("Api" + method) {
|
||||
exception.New("Method %s not found", 500, method).Throw()
|
||||
return nil
|
||||
}
|
||||
|
||||
res, err := scriptCtx.Call("Api"+method, args...)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
return nil
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,6 +219,43 @@ function __sui_store(elm) {
|
|||
};
|
||||
}
|
||||
|
||||
async function __sui_backend_call(
|
||||
route: string,
|
||||
method: string,
|
||||
...args: any
|
||||
): Promise<any> {
|
||||
const url = `/api/__yao/sui/v1/run${route}`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
Cookie: document.cookie,
|
||||
};
|
||||
const payload = { method, args };
|
||||
try {
|
||||
const body = JSON.stringify(payload);
|
||||
const response = await fetch(url, { method: "POST", headers, body: body });
|
||||
const text = await response.text();
|
||||
let data: any | null = null;
|
||||
if (text && text != "") {
|
||||
data = JSON.parse(text);
|
||||
}
|
||||
|
||||
if (response.status >= 400) {
|
||||
const message = data.message
|
||||
? data.message
|
||||
: `Failed to call ${route} ${method}`;
|
||||
const code = data.code ? data.code : 500;
|
||||
return Promise.reject({ message, code });
|
||||
}
|
||||
|
||||
return Promise.resolve(data);
|
||||
} catch (e) {
|
||||
const message = e.message ? e.message : `Failed to call ${route} ${method}`;
|
||||
const code = e.code ? e.code : 500;
|
||||
console.error(`[SUI] Failed to call ${route} ${method}:`, e);
|
||||
return Promise.reject({ message, code });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SUI Render
|
||||
* @param component
|
||||
|
|
|
|||
|
|
@ -170,8 +170,25 @@ class __Render {
|
|||
this.comp = comp;
|
||||
this.option = option;
|
||||
}
|
||||
async Render(name, data): Promise<string> {
|
||||
async Exec(name, data): Promise<string> {
|
||||
// @ts-ignore
|
||||
return __sui_render(this.comp, name, data, this.option);
|
||||
}
|
||||
}
|
||||
|
||||
function $Backend(route?: string) {
|
||||
route = route || window.location.pathname;
|
||||
return new __Backend(route);
|
||||
}
|
||||
|
||||
class __Backend {
|
||||
route = "";
|
||||
constructor(route) {
|
||||
this.route = route;
|
||||
}
|
||||
|
||||
async Call(method: string, ...args: any): Promise<any> {
|
||||
// @ts-ignore
|
||||
return await __sui_backend_call(this.route, method, ...args);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue