feat: added the paths module.
This commit is contained in:
parent
4df97fc21d
commit
c9eb64783f
7 changed files with 59 additions and 265 deletions
191
httpx/handler.go
191
httpx/handler.go
|
@ -1,191 +0,0 @@
|
|||
package httpx
|
||||
|
||||
import (
|
||||
//"github.com/d5/tengo/v2"
|
||||
"surdeus.su/util/tpp/mdx"
|
||||
"surdeus.su/util/tpp/htmlx"
|
||||
"surdeus.su/util/tpp"
|
||||
"path/filepath"
|
||||
"net/http"
|
||||
"context"
|
||||
"path"
|
||||
"mime"
|
||||
"log"
|
||||
"os"
|
||||
"io"
|
||||
)
|
||||
|
||||
var _ = http.Handler(&Handler{})
|
||||
|
||||
// The type describes behaviour
|
||||
// of handling stuff like in PHP.
|
||||
type Handler struct {
|
||||
// THe field represents
|
||||
// where we store site's
|
||||
// source files and request handlers.
|
||||
sourcePath string
|
||||
// Preprocessor must be set by user
|
||||
// to be able to bring custom features in.
|
||||
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
|
||||
|
||||
// The global map accessable from all the
|
||||
// request so you can keep the states
|
||||
// between requests.
|
||||
global any
|
||||
md *mdx.Markdown
|
||||
html *htmlx.HTML
|
||||
}
|
||||
|
||||
// Returns the new Handler with
|
||||
// specified preprocessor, source path,
|
||||
// preprocessor extension and the global value.
|
||||
func NewHandler(
|
||||
pp *tpp.Preprocessor,
|
||||
src, ext string,
|
||||
global any,
|
||||
) *Handler {
|
||||
ret := &Handler{}
|
||||
ret.sourcePath = src
|
||||
ret.ext = ext
|
||||
ret.pp = pp
|
||||
ret.global = global
|
||||
return ret
|
||||
}
|
||||
|
||||
// Returns the default tpp.Preprocessor suitable for
|
||||
// the most needs.
|
||||
func DefaultPP(mod string) *tpp.Preprocessor {
|
||||
t := tpp.NewTengo().SetPreCompile(func(
|
||||
ctx context.Context,
|
||||
s *tpp.Script,
|
||||
) {
|
||||
s.SetImportDir(mod)
|
||||
s.SetImports(&ModuleGetter{})
|
||||
s.EnableFileImport(true)
|
||||
|
||||
s.Add("__http_request__", ctx.Value(KeyRequest))
|
||||
s.Add("__global__", ctx.Value(KeyGlobal))
|
||||
s.Add("__markdown__", ctx.Value(KeyMarkdown))
|
||||
s.Add("__html__", ctx.Value(KeyHTML))
|
||||
}).SetPreCode(func(ctx context.Context) []byte {
|
||||
return []byte(`
|
||||
markdown := func(...args) {
|
||||
pp.write_raw(__markdown__(args...))
|
||||
}
|
||||
http := immutable({
|
||||
request : __http_request__
|
||||
})
|
||||
html := __html__
|
||||
context.http = http
|
||||
context.pp = pp
|
||||
context.global = __global__
|
||||
context.html = html
|
||||
import("./pre")(context)
|
||||
`)
|
||||
}).SetPostCode(func(ctx context.Context) []byte {
|
||||
return []byte(`
|
||||
import("./post")(context)
|
||||
`)
|
||||
})
|
||||
|
||||
return tpp.New(t)
|
||||
}
|
||||
|
||||
func (h *Handler) SetMD(md *mdx.Markdown) *Handler {
|
||||
h.md = md
|
||||
return h
|
||||
}
|
||||
func (h *Handler) SetHTML(html *htmlx.HTML) *Handler {
|
||||
h.html = html
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *Handler) ServeHTTP(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
) {
|
||||
shouldProcess := true
|
||||
urlPath := r.URL.Path
|
||||
// Cleaning URL path to prevent injections.
|
||||
urlPath = path.Clean(urlPath)
|
||||
urlExt := path.Ext(urlPath)
|
||||
|
||||
filePath := filepath.Join(
|
||||
filepath.FromSlash(h.sourcePath),
|
||||
filepath.FromSlash(urlPath),
|
||||
)
|
||||
filePathTpp := filePath + h.ext
|
||||
|
||||
//log.Println("pth:", urlPath, filePathTpp)
|
||||
file, err := os.Open(filePathTpp)
|
||||
if err != nil {
|
||||
shouldProcess = false
|
||||
file, err = os.Open(filePath)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//process := true
|
||||
fileData, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(
|
||||
r.Context(),
|
||||
KeyRequest,
|
||||
&Request{
|
||||
Request: r,
|
||||
},
|
||||
)
|
||||
|
||||
ctx = context.WithValue(
|
||||
ctx,
|
||||
KeyGlobal,
|
||||
h.global,
|
||||
)
|
||||
|
||||
ctx = context.WithValue(
|
||||
ctx,
|
||||
KeyMarkdown,
|
||||
h.md,
|
||||
)
|
||||
|
||||
ctx = context.WithValue(
|
||||
ctx,
|
||||
KeyHTML,
|
||||
h.html,
|
||||
)
|
||||
|
||||
// Setting before the code to let it change own
|
||||
// content type.
|
||||
contentType := mime.TypeByExtension(urlExt)
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
|
||||
processedData := fileData
|
||||
if shouldProcess {
|
||||
processedData, err = h.pp.Process(
|
||||
ctx,
|
||||
true,
|
||||
filePathTpp,
|
||||
fileData,
|
||||
)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
log.Printf(
|
||||
"Error: pp.Process(...): %s\n",
|
||||
err,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
w.Write(processedData)
|
||||
}
|
|
@ -1,24 +1,2 @@
|
|||
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)
|
||||
}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package httpx
|
||||
|
||||
import (
|
||||
|
||||
"github.com/d5/tengo/v2"
|
||||
//"github.com/d5/tengo/v2/stdlib"
|
||||
"surdeus.su/util/tpp/mdx"
|
||||
"surdeus.su/core/cli/mtool"
|
||||
"net/http"
|
||||
"log"
|
||||
//"context"
|
||||
)
|
||||
|
||||
// Context key type for internal usage.
|
||||
type CKey string
|
||||
|
||||
const (
|
||||
KeyRequest CKey = "http-request"
|
||||
KeyGlobal = "global"
|
||||
KeyMarkdown = "markdown"
|
||||
KeyHTML = "html"
|
||||
)
|
||||
|
||||
// Simple PHP-like server implementation.
|
||||
var Tool = mtool.T("tht").Func(func(flags *mtool.Flags) {
|
||||
var (
|
||||
addr, ext, src, mod string
|
||||
)
|
||||
|
||||
flags.StringVar(&addr, "addr", ":3000", "address to serve at")
|
||||
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()
|
||||
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: NewHandler(
|
||||
DefaultPP(mod),
|
||||
src, ext,
|
||||
map[string] tengo.Object{},
|
||||
).SetMD(mdx.MakeDefaultMarkdown()),
|
||||
}
|
||||
|
||||
log.Printf("Listening on %q\n", addr)
|
||||
err := srv.ListenAndServe()
|
||||
if err != nil {
|
||||
log.Printf("Error: srv.ListenAndServe(...): %s\n", err)
|
||||
}
|
||||
})
|
3
install.sh
Executable file
3
install.sh
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
go install
|
47
paths/main.go
Normal file
47
paths/main.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package paths
|
||||
|
||||
import (
|
||||
"github.com/d5/tengo/v2"
|
||||
"path"
|
||||
)
|
||||
|
||||
var Module = 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
|
||||
}
|
||||
}
|
||||
|
7
readme.md
Normal file
7
readme.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
# xgo
|
||||
|
||||
The Tengo extended modules.
|
||||
|
||||
The module implements Tengo modules and interpreter
|
||||
with them to make more complicated scripts.
|
||||
|
|
@ -21,6 +21,7 @@ import (
|
|||
import "surdeus.su/core/cli/mtool"
|
||||
import "surdeus.su/core/xgo/cjson"
|
||||
import "surdeus.su/core/xgo/logx"
|
||||
import "surdeus.su/core/xgo/paths"
|
||||
|
||||
const (
|
||||
sourceFileExt = ".xgo"
|
||||
|
@ -56,6 +57,7 @@ func Run(flags *mtool.Flags) {
|
|||
modules := stdlib.GetModuleMap(stdlib.AllModuleNames()...)
|
||||
modules.AddBuiltinModule("cjson", cjson.Module)
|
||||
modules.AddBuiltinModule("log", logx.Module)
|
||||
modules.AddBuiltinModule("paths", paths.Module)
|
||||
if len(iargs) == 0 {
|
||||
// REPL
|
||||
RunREPL(modules, os.Stdin, os.Stdout)
|
||||
|
|
Loading…
Reference in a new issue