[add] sui page render (dev)

This commit is contained in:
Max 2023-11-23 17:16:51 +08:00
parent dc91443217
commit b0e94e3d73
6 changed files with 148 additions and 32 deletions

View file

@ -2,11 +2,14 @@ package api
import ( import (
"fmt" "fmt"
"net/url"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/yaoapp/gou/application" "github.com/yaoapp/gou/application"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/sui/core" "github.com/yaoapp/yao/sui/core"
) )
@ -37,7 +40,7 @@ func NewRequestContext(c *gin.Context) (*Request, int, error) {
Body: body, Body: body,
Payload: payload, Payload: payload,
Referer: c.Request.Referer(), Referer: c.Request.Referer(),
Headers: c.Request.Header, Headers: url.Values(c.Request.Header),
Params: params, Params: params,
}, },
}, 200, nil }, 200, nil
@ -45,7 +48,53 @@ func NewRequestContext(c *gin.Context) (*Request, int, error) {
// Render is the response for the page API. // Render is the response for the page API.
func (r *Request) Render() (string, int, error) { func (r *Request) Render() (string, int, error) {
return r.File, 200, nil
c := core.GetCache(r.File)
if c == nil {
// Read the file
content, err := application.App.Read(r.File)
if err != nil {
return "", 404, err
}
doc, err := core.NewDocument(content)
if err != nil {
return "", 500, err
}
dataText := ""
dataSel := doc.Find("script[name=data]")
if dataSel != nil && dataSel.Length() > 0 {
dataText = dataSel.Text()
dataSel.Remove()
}
html, err := doc.Html()
if err != nil {
return "", 500, fmt.Errorf("parse error, please re-complie the page %s", err.Error())
}
// Save to The Cache
c = core.SetCache(r.File, html, dataText)
log.Trace("The page %s is cached", r.File)
}
var err error
data := core.Data{}
if c.Data != "" {
data, err = r.Request.ExecString(c.Data)
if err != nil {
return "", 500, fmt.Errorf("data error, please re-complie the page %s", err.Error())
}
}
parser := core.NewTemplateParser(data, nil)
html, err := parser.Render(c.HTML)
if err != nil {
return "", 500, fmt.Errorf("render error, please re-complie the page %s", err.Error())
}
return html, 200, nil
} }
func parserPath(c *gin.Context) (string, map[string]string, error) { func parserPath(c *gin.Context) (string, map[string]string, error) {
@ -57,7 +106,7 @@ func parserPath(c *gin.Context) (string, map[string]string, error) {
return "", nil, fmt.Errorf("no route matchers") return "", nil, fmt.Errorf("no route matchers")
} }
fileParts := []string{application.App.Root(), "public"} fileParts := []string{string(os.PathSeparator), "public"}
// Match the sui // Match the sui
matchers := core.RouteExactMatchers[parts[0]] matchers := core.RouteExactMatchers[parts[0]]
@ -101,7 +150,7 @@ func parserPath(c *gin.Context) (string, map[string]string, error) {
} else if matcher.Regex != nil { } else if matcher.Regex != nil {
if matcher.Regex.MatchString(part) { if matcher.Regex.MatchString(part) {
file := matcher.Ref.(string) file := matcher.Ref
key := strings.TrimRight(strings.TrimLeft(file, "["), "]") key := strings.TrimRight(strings.TrimLeft(file, "["), "]")
params[key] = part params[key] = part
fileParts = append(fileParts, file) fileParts = append(fileParts, file)

View file

@ -1,7 +1,6 @@
package core package core
import ( import (
"fmt"
"regexp" "regexp"
"github.com/evanw/esbuild/pkg/api" "github.com/evanw/esbuild/pkg/api"
@ -30,13 +29,13 @@ func (page *Page) Compile(option *BuildOption) (string, error) {
) )
} }
// add the route data // // add the route data
doc.Find("body").AppendHtml(`<script name="route" type="json">` + "\n" + // doc.Find("body").AppendHtml(`<script name="route" type="json">` + "\n" +
fmt.Sprintf( // fmt.Sprintf(
`{"sui": "%s", "template": "%s", "route": "%s"}`, // `{"sui": "%s", "template": "%s", "route": "%s"}`,
page.SuiID, page.TemplateID, page.Route, // page.SuiID, page.TemplateID, page.Route,
) + // ) +
"\n</script>\n") // "\n</script>\n")
html, err := doc.Html() html, err := doc.Html()
if err != nil { if err != nil {

View file

@ -9,6 +9,15 @@ import (
"github.com/yaoapp/kun/any" "github.com/yaoapp/kun/any"
) )
// Cache the cache
type Cache struct {
Data string
HTML string
}
// Caches the caches
var Caches = map[string]*Cache{}
// ExecString get the data // ExecString get the data
func (r *Request) ExecString(data string) (Data, error) { func (r *Request) ExecString(data string) (Data, error) {
var res Data var res Data
@ -50,6 +59,39 @@ func (r *Request) Exec(m Data) error {
func (r *Request) execValue(value interface{}) (interface{}, error) { func (r *Request) execValue(value interface{}) (interface{}, error) {
switch v := value.(type) { switch v := value.(type) {
case string: case string:
if strings.HasPrefix(v, "$query.") {
key := strings.TrimLeft(v, "$query.")
if r.Query.Has(key) {
return r.Query.Get(key), nil
}
return "", nil
}
if strings.HasPrefix(v, "$header.") {
key := strings.TrimLeft(v, "$header.")
if r.Headers.Has(key) {
return r.Headers.Get(key), nil
}
return "", nil
}
if strings.HasPrefix(v, "$param.") {
key := strings.TrimLeft(v, "$param.")
if value, has := r.Params[key]; has {
return value, nil
}
return "", nil
}
if strings.HasPrefix(v, "$payload.") {
key := strings.TrimLeft(v, "$payload.")
if value, has := r.Payload[key]; has {
return value, nil
}
return "", nil
}
if strings.HasPrefix(v, "$") { if strings.HasPrefix(v, "$") {
return r.call(strings.TrimLeft(v, "$")) return r.call(strings.TrimLeft(v, "$"))
} }
@ -127,6 +169,10 @@ func (r *Request) call(p interface{}) (interface{}, error) {
return nil, err return nil, err
} }
if r.Sid != "" {
process.WithSID(r.Sid)
}
return process.Exec() return process.Exec()
} }
@ -183,3 +229,30 @@ func (r *Request) parseArgs(args []interface{}) ([]interface{}, error) {
return args, nil return args, nil
} }
// SetCache set the cache
func SetCache(file string, html string, data string) *Cache {
Caches[file] = &Cache{
Data: data,
HTML: html,
}
return Caches[file]
}
// GetCache get the cache
func GetCache(file string) *Cache {
if cache, has := Caches[file]; has {
return cache
}
return nil
}
// RemoveCache remove the cache
func RemoveCache(file string) {
delete(Caches, file)
}
// CleanCache clean the cache
func CleanCache() {
Caches = map[string]*Cache{}
}

View file

@ -30,7 +30,6 @@ func (sui *DSL) WithSid(sid string) {
// PublicRootMatcher returns the public root matcher // PublicRootMatcher returns the public root matcher
func (sui *DSL) PublicRootMatcher() *Matcher { func (sui *DSL) PublicRootMatcher() *Matcher {
var ref SUI = sui
pub := sui.GetPublic() pub := sui.GetPublic()
if varRe.MatchString(pub.Root) { if varRe.MatchString(pub.Root) {
if pub.Matcher != "" { if pub.Matcher != "" {
@ -41,9 +40,9 @@ func (sui *DSL) PublicRootMatcher() *Matcher {
} }
return &Matcher{Regex: re} return &Matcher{Regex: re}
} }
return &Matcher{Regex: RouteRegexp, Ref: ref} return &Matcher{Regex: RouteRegexp}
} }
return &Matcher{Exact: pub.Root, Ref: ref} return &Matcher{Exact: pub.Root}
} }
// PublicRoot returns the public root path // PublicRoot returns the public root path

View file

@ -147,8 +147,9 @@ type Request struct {
Payload map[string]interface{} `json:"payload,omitempty"` Payload map[string]interface{} `json:"payload,omitempty"`
Query url.Values `json:"query,omitempty"` Query url.Values `json:"query,omitempty"`
Params map[string]string `json:"params,omitempty"` Params map[string]string `json:"params,omitempty"`
Headers map[string][]string `json:"headers,omitempty"` Headers url.Values `json:"headers,omitempty"`
Body interface{} `json:"body,omitempty"` Body interface{} `json:"body,omitempty"`
Sid string `json:"sid,omitempty"`
Theme string `json:"theme,omitempty"` Theme string `json:"theme,omitempty"`
Locale string `json:"locale,omitempty"` Locale string `json:"locale,omitempty"`
} }
@ -266,7 +267,7 @@ type Matcher struct {
Regex *regexp.Regexp `json:"regex,omitempty"` Regex *regexp.Regexp `json:"regex,omitempty"`
Exact string `json:"exact,omitempty"` Exact string `json:"exact,omitempty"`
Parent string `json:"-"` Parent string `json:"-"`
Ref interface{} `json:"-"` Ref string `json:"-"`
} }
// DocumentDefault is the default document // DocumentDefault is the default document

View file

@ -99,28 +99,23 @@ func (page *Page) publicFile() string {
log.Error("publicFile: Get the public root error: %s. use %s", err.Error(), page.tmpl.local.DSL.Public.Root) log.Error("publicFile: Get the public root error: %s. use %s", err.Error(), page.tmpl.local.DSL.Public.Root)
root = page.tmpl.local.DSL.Public.Root root = page.tmpl.local.DSL.Public.Root
} }
return filepath.Join(application.App.Root(), "public", root, page.Route) return filepath.Join("/", "public", root, page.Route)
} }
// writeHTMLTo write the html to file // writeHTMLTo write the html to file
func (page *Page) writeHTML(html []byte) error { func (page *Page) writeHTML(html []byte) error {
htmlFile := fmt.Sprintf("%s.sui", page.publicFile()) htmlFile := fmt.Sprintf("%s.sui", page.publicFile())
dir := filepath.Dir(htmlFile) htmlFileAbs := filepath.Join(application.App.Root(), htmlFile)
dir := filepath.Dir(htmlFileAbs)
if exist, _ := os.Stat(dir); exist == nil { if exist, _ := os.Stat(dir); exist == nil {
os.MkdirAll(dir, os.ModePerm) os.MkdirAll(dir, os.ModePerm)
} }
return os.WriteFile(htmlFile, html, 0644) err := os.WriteFile(htmlFileAbs, html, 0644)
if err != nil {
return err
} }
// writeHTMLTo write the html to file core.RemoveCache(htmlFile)
func (page *Page) writeData() error { log.Trace("The page %s is removed", htmlFile)
if page.Codes.DATA.Code == "" {
return nil return nil
} }
dataFile := fmt.Sprintf("%s.json", page.publicFile())
dir := filepath.Dir(dataFile)
if exist, _ := os.Stat(dir); exist == nil {
os.MkdirAll(dir, os.ModePerm)
}
return os.WriteFile(dataFile, []byte(page.Codes.DATA.Code), 0644)
}