From 502cfbe3901399dfddd1dd508177c466677efae2 Mon Sep 17 00:00:00 2001 From: surdeus Date: Fri, 17 May 2024 22:46:34 +0500 Subject: [PATCH] feat: made better interfaces and more generalized approach to use THT. --- cmd/tht/main.go | 3 +- cmd/tpp/main.go | 2 +- go.mod | 2 +- httpx/handler.go | 36 ++++++++++---- httpx/module.go | 24 ++++++++++ httpx/request.go | 9 ++++ httpx/tool.go | 40 +++++++++------- mod/post.tengo | 22 +++++++++ mod/pre.tengo | 26 ++++++++++ paths/main.go | 51 ++++++++++++++++++++ src/main.htm.tpp | 41 ++++++++-------- tengo.go | 120 +++++++++++++++++++++-------------------------- 12 files changed, 259 insertions(+), 117 deletions(-) create mode 100644 httpx/module.go create mode 100644 mod/post.tengo create mode 100644 mod/pre.tengo create mode 100644 paths/main.go diff --git a/cmd/tht/main.go b/cmd/tht/main.go index 5fffc86..3170fd7 100644 --- a/cmd/tht/main.go +++ b/cmd/tht/main.go @@ -1,11 +1,10 @@ package main import ( - "vultras.su/util/tpp/httpx" + "surdeus.su/util/tpp/httpx" "os" ) func main() { httpx.Tool.Run(os.Args[1:]) } - diff --git a/cmd/tpp/main.go b/cmd/tpp/main.go index a827a8b..1349e3d 100644 --- a/cmd/tpp/main.go +++ b/cmd/tpp/main.go @@ -1,7 +1,7 @@ package main import ( - "vultras.su/util/tpp" + "surdeus.su/util/tpp" "os" ) diff --git a/go.mod b/go.mod index 9623bd2..c317a32 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module vultras.su/util/tpp +module surdeus.su/util/tpp go 1.21.7 diff --git a/httpx/handler.go b/httpx/handler.go index 3140ba3..f85eccf 100644 --- a/httpx/handler.go +++ b/httpx/handler.go @@ -1,7 +1,7 @@ package httpx import ( - "vultras.su/util/tpp" + "surdeus.su/util/tpp" "path/filepath" "net/http" "context" @@ -20,14 +20,28 @@ type Handler struct { // THe field represents // where we store site's // source files and request handlers. - SourcePath string + sourcePath string // Preprocessor must be set by user // to be able to bring custom features in. - PP *tpp.Preprocessor + pp *tpp.Preprocessor // Aditional extension. ".tpp" by default. // For example "file.html.tpp" will be // first preprocessed TPP and sent back as simple HTML. - Ext string + ext string +} + +// Returns the new Handler with +// specified preprocessor, source path and +// extension. +func NewHandler( + pp *tpp.Preprocessor, + src, ext string, +) *Handler { + ret := &Handler{} + ret.sourcePath = src + ret.ext = ext + ret.pp = pp + return ret } func (h *Handler) ServeHTTP( @@ -40,10 +54,10 @@ func (h *Handler) ServeHTTP( urlExt := path.Ext(urlPath) filePath := filepath.Join( - filepath.FromSlash(h.SourcePath), + filepath.FromSlash(h.sourcePath), filepath.FromSlash(urlPath), ) - filePathTpp := filePath + h.Ext + filePathTpp := filePath + h.ext //log.Println("pth:", urlPath, filePathTpp) file, err := os.Open(filePathTpp) @@ -62,7 +76,13 @@ func (h *Handler) ServeHTTP( ctx := context.WithValue(r.Context(), KeyRequest, &Request{ Request: r, }) - processedData, err := h.PP.Process( + + // Setting before the code to let it change own + // content type. + contentType := mime.TypeByExtension(urlExt) + w.Header().Set("Content-Type", contentType) + + processedData, err := h.pp.Process( ctx, true, filePathTpp, @@ -74,7 +94,5 @@ func (h *Handler) ServeHTTP( return } - contentType := mime.TypeByExtension(urlExt) - w.Header().Set("Content-Type", contentType) w.Write(processedData) } diff --git a/httpx/module.go b/httpx/module.go new file mode 100644 index 0000000..f7a0765 --- /dev/null +++ b/httpx/module.go @@ -0,0 +1,24 @@ +package httpx + +import "github.com/d5/tengo/v2" +import "github.com/d5/tengo/v2/stdlib" +import "surdeus.su/util/tpp/paths" + +var Modules = map[string]tengo.Importable{ + "paths": paths.Module, +} + +var Stdlib = stdlib.GetModuleMap(stdlib.AllModuleNames()...) + +type ModuleGetter struct{} + +func (m *ModuleGetter) Get( + name string, +) tengo.Importable { + module, exist := Modules[name] + if exist { + return module + } + + return Stdlib.Get(name) +} diff --git a/httpx/request.go b/httpx/request.go index eab9480..8f72830 100644 --- a/httpx/request.go +++ b/httpx/request.go @@ -3,6 +3,7 @@ package httpx import ( "github.com/d5/tengo/v2" "net/http" + "io" //"log" ) @@ -32,6 +33,14 @@ func (r *Request) IndexGet( return &URL{ URL: r.URL, }, nil + case "body" : + bts, err := io.ReadAll(r.Body) + if err != nil { + return nil, err + } + return &tengo.Bytes{ + Value: bts, + }, nil } // Nothing found. diff --git a/httpx/tool.go b/httpx/tool.go index d745182..4cc613a 100644 --- a/httpx/tool.go +++ b/httpx/tool.go @@ -2,8 +2,8 @@ package httpx import ( //"github.com/d5/tengo/v2" - "github.com/d5/tengo/v2/stdlib" - "vultras.su/util/tpp" + //"github.com/d5/tengo/v2/stdlib" + "surdeus.su/util/tpp" "vultras.su/core/cli/mtool" "net/http" "log" @@ -12,47 +12,53 @@ import ( // Context key type for internal usage. type CKey string + const ( KeyRequest CKey = "http-request" ) // Simple PHP-like server implementation. -var Tool = mtool.T("tht").Func(func(flags *mtool.Flags){ +var Tool = mtool.T("tht").Func(func(flags *mtool.Flags) { var ( - addr string - handler Handler + addr, ext, src, mod string ) flags.StringVar(&addr, "addr", ":3000", "address to serve at") - flags.StringVar(&handler.SourcePath, "src", "./src", "directory with source files") - flags.StringVar(&handler.Ext, "ext", ".tpp", "extension for TPP files") + flags.StringVar(&mod, "mod", "./mod", "path to store Tengo modules") + flags.StringVar(&src, "src", "./src", "directory with source files") + flags.StringVar(&ext, "ext", ".tpp", "extension for TPP files") flags.Parse() t := tpp.NewTengo().SetPreCompile(func( ctx context.Context, s *tpp.Script, - ){ - s.SetImportDir(handler.SourcePath) - s.SetImports(stdlib.GetModuleMap( - stdlib.AllModuleNames()..., - )) + ) { + s.SetImportDir(mod) + s.SetImports(&ModuleGetter{}) s.EnableFileImport(true) s.Add("__http_request__", ctx.Value(KeyRequest)) }).SetPreCode(func(ctx context.Context) []byte { return []byte(` - http := { + http := immutable({ request : __http_request__ + }) + __context__ := { + http: http, + pp: pp } + import("./pre")(__context__) + `) + }).SetPostCode(func(ctx context.Context) []byte { + return []byte(` + import("./post")(__context__) `) }) - handler.PP = tpp.New(t) - srv := &http.Server{ - Addr: addr, - Handler: &handler, + Addr: addr, + Handler: NewHandler(tpp.New(t), src, ext), } err := srv.ListenAndServe() if err != nil { diff --git a/mod/post.tengo b/mod/post.tengo new file mode 100644 index 0000000..12086f1 --- /dev/null +++ b/mod/post.tengo @@ -0,0 +1,22 @@ +fmt := import("fmt") +paths := import("paths") +htmExt := func(c){ + c.pp.print(` + + `) +} + +exts := { + ".htm": htmExt, + ".html": htmExt +} + +export func(c){ + url_path := c.http.request.url.path + ext := paths.ext(url_path) + + cl := exts[ext] + if !is_undefined(cl) { + cl(c) + } +} diff --git a/mod/pre.tengo b/mod/pre.tengo new file mode 100644 index 0000000..e7c7c7c --- /dev/null +++ b/mod/pre.tengo @@ -0,0 +1,26 @@ +fmt := import("fmt") +paths := import("paths") + +htmExt := func(c){ + c.pp.print(` + + + Check shit + + `) +} + +exts := { + ".htm": htmExt, + ".html": htmExt +} + +export func(c){ + url_path := c.http.request.url.path + ext := paths.ext(url_path) + + cl := exts[ext] + if !is_undefined(cl) { + cl(c) + } +} diff --git a/paths/main.go b/paths/main.go new file mode 100644 index 0000000..6c54566 --- /dev/null +++ b/paths/main.go @@ -0,0 +1,51 @@ +package paths + +import ( + "github.com/d5/tengo/v2" + "path" +) + +var Module = &tengo.BuiltinModule { + Attrs: moduleMap, +} + +var moduleMap = map[string] tengo.Object { + "base" : &tengo.UserFunction{ + Name: "base", + Value: wrapOneArg(path.Base), + }, + "ext" : &tengo.UserFunction{ + Name: "ext", + Value: wrapOneArg(path.Ext), + }, + "dir" : &tengo.UserFunction{ + Name: "dir", + Value: wrapOneArg(path.Dir), + }, + "clean" : &tengo.UserFunction{ + Name: "clean", + Value: wrapOneArg(path.Clean), + }, +} + +func wrapOneArg( + fn func(string) string, +) func(...tengo.Object) (tengo.Object, error) { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + str, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + return &tengo.String{ + Value: fn(str), + }, nil + } +} + diff --git a/src/main.htm.tpp b/src/main.htm.tpp index d19279b..343e5b4 100644 --- a/src/main.htm.tpp +++ b/src/main.htm.tpp @@ -4,26 +4,27 @@ q := req.url.query // List checking. list := [1, 2, 3, 4, 123] + body := req.body + if body { + fmt.println(string(body)) + } +}} -}} - - +{{ + if q.name { + pp.print("
", q.name[0], "
") + } +}} +
+ Hello, Cock! +
+
{{ - if q.name { - pp.print("
", q.name[0], "
") - } + pp.print(req.url.path) }} -
- Hello, Cock! -
-
- {{ - pp.print(req.url.path) - }} -
- - +
+ diff --git a/tengo.go b/tengo.go index b962761..8eff28f 100644 --- a/tengo.go +++ b/tengo.go @@ -53,7 +53,8 @@ func (pp *Tengo) Eval( var fullCodeBuf bytes.Buffer const retHead = ` __ret_one__ := bytes("") - pp := { + pp := immutable({ + filepath: __filepath__, printf : func(format, ...vals) { __ret_one__ += __sprintf__(format, vals...) }, @@ -67,7 +68,7 @@ func (pp *Tengo) Eval( write_raw : func(bts) { __ret_one__ += bytes(bts) } - } + }) ` @@ -94,78 +95,63 @@ func (pp *Tengo) Eval( pp.preCompile(ctx, script) } - err := script.Add("__sprintf__", &tengo.UserFunction{ - Value: func(args ...tengo.Object) (tengo.Object, error){ - if len(args) < 1 { - return nil, tengo.ErrWrongNumArguments + script.Add("__filepath__", filePath) + script.Add("__sprintf__", &tengo.UserFunction{ + Value: func(args ...tengo.Object) (tengo.Object, error){ + if len(args) < 1 { + return nil, tengo.ErrWrongNumArguments + } + format, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Expected: "string", } - format, ok := tengo.ToString(args[0]) - if !ok { - return nil, tengo.ErrInvalidArgumentType{ - Expected: "string", - } - } - gargs := make([]any, len(args) - 1) - for i := range gargs { - gargs[i] = tengo.ToInterface(args[i+1]) - //fmt.Printf("shit: %q\n", gargs[i]) - } - str := fmt.Sprintf(format, gargs...) - return tengo.FromInterface([]byte(str)) - }, + } + gargs := make([]any, len(args) - 1) + for i := range gargs { + gargs[i] = tengo.ToInterface(args[i+1]) + //fmt.Printf("shit: %q\n", gargs[i]) + } + str := fmt.Sprintf(format, gargs...) + return tengo.FromInterface([]byte(str)) }, - ) - if err != nil { - return nil, err - } - err = script.Add("__sprint__", &tengo.UserFunction{ - Value: func(args ...tengo.Object) (tengo.Object, error){ - gargs := make([]any, len(args)) - for i := range gargs { - gargs[i] = tengo.ToInterface(args[i]) - } - str := fmt.Sprint(gargs...) - return tengo.FromInterface([]byte(str)) - }, + }) + script.Add("__sprint__", &tengo.UserFunction{ + Value: func(args ...tengo.Object) (tengo.Object, error){ + gargs := make([]any, len(args)) + for i := range gargs { + gargs[i] = tengo.ToInterface(args[i]) + } + str := fmt.Sprint(gargs...) + return tengo.FromInterface([]byte(str)) }, - ) - if err != nil { - return nil, err - } - err = script.Add("__sprintln__", &tengo.UserFunction{ - Value: func(args ...tengo.Object) (tengo.Object, error){ - gargs := make([]any, len(args)) - for i := range gargs { - gargs[i] = tengo.ToInterface(args[i]) - } - str := fmt.Sprintln(gargs...) - return tengo.FromInterface([]byte(str)) - }, + }) + script.Add("__sprintln__", &tengo.UserFunction{ + Value: func(args ...tengo.Object) (tengo.Object, error){ + gargs := make([]any, len(args)) + for i := range gargs { + gargs[i] = tengo.ToInterface(args[i]) + } + str := fmt.Sprintln(gargs...) + return tengo.FromInterface([]byte(str)) }, - ) - if err != nil { - return nil, err - } - err = script.Add("__separate__", &tengo.UserFunction{ - Value: func(args ...tengo.Object) (tengo.Object, error){ - if len(args) < 1 { - return nil, tengo.ErrWrongNumArguments + }) + script.Add("__separate__", &tengo.UserFunction{ + Value: func(args ...tengo.Object) (tengo.Object, error){ + if len(args) < 1 { + return nil, tengo.ErrWrongNumArguments + } + bts, ok := tengo.ToByteSlice(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ } - bts, ok := tengo.ToByteSlice(args[0]) - if !ok { - return nil, tengo.ErrInvalidArgumentType{ - } - } - rets = append(rets, bts) - return nil, nil - }, + } + rets = append(rets, bts) + return nil, nil }, - ) - if err != nil { - return nil, err - } + }) - _, err = script.RunContext(ctx) + _, err := script.RunContext(ctx) if err != nil { return nil, err }