2024-06-09 16:26:31 +03:00
|
|
|
package tht
|
2024-06-09 15:16:38 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
//"github.com/d5/tengo/v2"
|
2024-06-09 16:26:31 +03:00
|
|
|
"surdeus.su/util/tht/mdx"
|
2024-06-09 15:16:38 +03:00
|
|
|
//"surdeus.su/core/xgo/xmodules/htmlx"
|
|
|
|
"surdeus.su/core/xgo/xmodules/httpx"
|
|
|
|
"surdeus.su/core/xgo/xmodules"
|
|
|
|
"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
|
|
|
|
indexSuffix string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the new Handler with
|
|
|
|
// specified preprocessor, source path,
|
|
|
|
// preprocessor extension and the global value.
|
|
|
|
func NewHandler(
|
|
|
|
pp *tpp.Preprocessor,
|
|
|
|
src, ext, index string,
|
|
|
|
global any,
|
|
|
|
) *Handler {
|
|
|
|
ret := &Handler{}
|
|
|
|
ret.sourcePath = src
|
|
|
|
ret.ext = ext
|
|
|
|
ret.pp = pp
|
|
|
|
ret.global = global
|
|
|
|
ret.indexSuffix = index
|
|
|
|
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(xmodules.Modules)
|
|
|
|
s.EnableFileImport(true)
|
|
|
|
|
|
|
|
s.Add("__http_request__", ctx.Value(KeyRequest))
|
|
|
|
s.Add("__global__", ctx.Value(KeyGlobal))
|
|
|
|
s.Add("__markdown__", ctx.Value(KeyMarkdown))
|
|
|
|
}).SetPreCode(func(ctx context.Context) []byte {
|
|
|
|
return []byte(`
|
|
|
|
markdown := func(...args) {
|
|
|
|
pp.write_raw(__markdown__(args...))
|
|
|
|
}
|
|
|
|
__http__ := immutable({
|
|
|
|
request : __http_request__
|
|
|
|
})
|
|
|
|
context.http = __http__
|
|
|
|
context.pp = pp
|
|
|
|
context.global = __global__
|
|
|
|
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) ServeHTTP(
|
|
|
|
w http.ResponseWriter,
|
|
|
|
r *http.Request,
|
|
|
|
) {
|
|
|
|
shouldProcess := true
|
|
|
|
urlPath := r.URL.Path
|
|
|
|
// Cleaning URL path to prevent injections.
|
|
|
|
urlPath = path.Clean(urlPath)
|
2024-06-09 19:43:16 +03:00
|
|
|
urlExt := path.Ext(urlPath)
|
|
|
|
if urlExt == h.ext {
|
|
|
|
http.NotFound(w, r)
|
|
|
|
return
|
|
|
|
}
|
2024-06-09 15:16:38 +03:00
|
|
|
|
|
|
|
filePath := filepath.Join(
|
|
|
|
filepath.FromSlash(h.sourcePath),
|
|
|
|
filepath.FromSlash(urlPath),
|
|
|
|
)
|
|
|
|
fileStat, err := os.Stat(filePath)
|
|
|
|
if err == nil {
|
|
|
|
if fileStat.IsDir() {
|
|
|
|
filePath = filepath.Join(
|
|
|
|
filePath,
|
|
|
|
h.indexSuffix,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
&httpx.Request{
|
|
|
|
Request: r,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx = context.WithValue(
|
|
|
|
ctx,
|
|
|
|
KeyGlobal,
|
|
|
|
h.global,
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx = context.WithValue(
|
|
|
|
ctx,
|
|
|
|
KeyMarkdown,
|
|
|
|
h.md,
|
|
|
|
)
|
|
|
|
|
|
|
|
// Setting before the code to let it change own
|
|
|
|
// content type?
|
2024-06-09 17:47:01 +03:00
|
|
|
fileExt := filepath.Ext(filePath)
|
|
|
|
contentType := mime.TypeByExtension(fileExt)
|
2024-06-09 15:16:38 +03:00
|
|
|
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)
|
|
|
|
}
|