[add] sui page render (dev)
This commit is contained in:
parent
dc91443217
commit
b0e94e3d73
6 changed files with 148 additions and 32 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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{}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue