feat: made better interfaces and more generalized approach to use THT.

This commit is contained in:
Andrey Parhomenko 2024-05-17 22:46:34 +05:00
parent 8ac7b3bb31
commit 502cfbe390
12 changed files with 259 additions and 117 deletions

View file

@ -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:])
}

View file

@ -1,7 +1,7 @@
package main
import (
"vultras.su/util/tpp"
"surdeus.su/util/tpp"
"os"
)

2
go.mod
View file

@ -1,4 +1,4 @@
module vultras.su/util/tpp
module surdeus.su/util/tpp
go 1.21.7

View file

@ -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)
}

24
httpx/module.go Normal file
View file

@ -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)
}

View file

@ -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.

View file

@ -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,6 +12,7 @@ import (
// Context key type for internal usage.
type CKey string
const (
KeyRequest CKey = "http-request"
)
@ -19,13 +20,13 @@ const (
// Simple PHP-like server implementation.
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()
@ -33,26 +34,31 @@ var Tool = mtool.T("tht").Func(func(flags *mtool.Flags){
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,
Handler: NewHandler(tpp.New(t), src, ext),
}
err := srv.ListenAndServe()
if err != nil {

22
mod/post.tengo Normal file
View file

@ -0,0 +1,22 @@
fmt := import("fmt")
paths := import("paths")
htmExt := func(c){
c.pp.print(`
</body></html>
`)
}
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)
}
}

26
mod/pre.tengo Normal file
View file

@ -0,0 +1,26 @@
fmt := import("fmt")
paths := import("paths")
htmExt := func(c){
c.pp.print(`
<!doctype html>
<html><head>
<title>Check shit</title>
</head><body>
`)
}
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)
}
}

51
paths/main.go Normal file
View file

@ -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
}
}

View file

@ -4,10 +4,12 @@
q := req.url.query
// List checking.
list := [1, 2, 3, 4, 123]
body := req.body
if body {
fmt.println(string(body))
}
}}
}}<!doctype html>
<html><head>
</head><body>
{{
if q.name {
pp.print("<div id=\"name\">", q.name[0], "</div>")
@ -26,4 +28,3 @@
pp.print("<li>", v, "</li>")
}
}}</ul>
</body></html>

View file

@ -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,7 +95,8 @@ func (pp *Tengo) Eval(
pp.preCompile(ctx, script)
}
err := script.Add("__sprintf__", &tengo.UserFunction{
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
@ -113,12 +115,8 @@ func (pp *Tengo) Eval(
str := fmt.Sprintf(format, gargs...)
return tengo.FromInterface([]byte(str))
},
},
)
if err != nil {
return nil, err
}
err = script.Add("__sprint__", &tengo.UserFunction{
})
script.Add("__sprint__", &tengo.UserFunction{
Value: func(args ...tengo.Object) (tengo.Object, error){
gargs := make([]any, len(args))
for i := range gargs {
@ -127,12 +125,8 @@ func (pp *Tengo) Eval(
str := fmt.Sprint(gargs...)
return tengo.FromInterface([]byte(str))
},
},
)
if err != nil {
return nil, err
}
err = script.Add("__sprintln__", &tengo.UserFunction{
})
script.Add("__sprintln__", &tengo.UserFunction{
Value: func(args ...tengo.Object) (tengo.Object, error){
gargs := make([]any, len(args))
for i := range gargs {
@ -141,12 +135,8 @@ func (pp *Tengo) Eval(
str := fmt.Sprintln(gargs...)
return tengo.FromInterface([]byte(str))
},
},
)
if err != nil {
return nil, err
}
err = script.Add("__separate__", &tengo.UserFunction{
})
script.Add("__separate__", &tengo.UserFunction{
Value: func(args ...tengo.Object) (tengo.Object, error){
if len(args) < 1 {
return nil, tengo.ErrWrongNumArguments
@ -159,13 +149,9 @@ func (pp *Tengo) Eval(
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
}