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,
|
|
|
|
) {
|
2024-06-18 15:34:12 +03:00
|
|
|
|
2024-06-09 15:16:38 +03:00
|
|
|
s.SetImportDir(mod)
|
2024-06-18 15:34:12 +03:00
|
|
|
modules := xmodules.GetModules()
|
|
|
|
modules.Add("markdown", mdx.GetModule())
|
|
|
|
s.SetImports(modules)
|
2024-06-09 15:16:38 +03:00
|
|
|
s.EnableFileImport(true)
|
|
|
|
|
2024-06-12 22:02:26 +03:00
|
|
|
vals := ctx.Value(KeyValues).(*ContextValues)
|
|
|
|
s.Add("__http_request__", vals.Request)
|
|
|
|
s.Add("__global__", vals.Global)
|
|
|
|
s.Add("__markdown__", vals.Markdown)
|
|
|
|
s.Add("__is_index__", vals.IsIndex)
|
|
|
|
s.Add("__index_suffix__", vals.IndexSuffix)
|
|
|
|
s.Add("__tpp_ext__", vals.Ext)
|
2024-06-14 21:53:29 +03:00
|
|
|
s.Add("__source_path__", vals.SourcePath)
|
2024-06-18 15:34:12 +03:00
|
|
|
|
2024-06-09 15:16:38 +03:00
|
|
|
}).SetPreCode(func(ctx context.Context) []byte {
|
|
|
|
return []byte(`
|
|
|
|
markdown := func(...args) {
|
|
|
|
pp.write_raw(__markdown__(args...))
|
|
|
|
}
|
|
|
|
__http__ := immutable({
|
|
|
|
request : __http_request__
|
|
|
|
})
|
2024-06-12 22:02:26 +03:00
|
|
|
|
2024-06-09 15:16:38 +03:00
|
|
|
context.http = __http__
|
|
|
|
context.pp = pp
|
|
|
|
context.global = __global__
|
2024-06-12 22:02:26 +03:00
|
|
|
context.is_index = __is_index__
|
|
|
|
context.index_suffix = __index_suffix__
|
|
|
|
context.tpp_ext = __tpp_ext__
|
2024-06-14 21:53:29 +03:00
|
|
|
context.source_path = __source_path__
|
2024-06-12 22:02:26 +03:00
|
|
|
|
2024-06-09 15:16:38 +03:00
|
|
|
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,
|
|
|
|
) {
|
2024-06-12 22:02:26 +03:00
|
|
|
isIndex := false
|
2024-06-09 15:16:38 +03:00
|
|
|
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,
|
|
|
|
)
|
2024-06-12 22:02:26 +03:00
|
|
|
isIndex = true
|
2024-06-09 15:16:38 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-06-12 22:02:26 +03:00
|
|
|
|
2024-06-09 15:16:38 +03:00
|
|
|
ctx := context.WithValue(
|
|
|
|
r.Context(),
|
2024-06-12 22:02:26 +03:00
|
|
|
KeyValues,
|
|
|
|
&ContextValues{
|
|
|
|
Request: &httpx.Request{
|
|
|
|
Request: r,
|
|
|
|
},
|
|
|
|
Global: h.global,
|
|
|
|
Markdown: h.md,
|
|
|
|
IsIndex: isIndex,
|
|
|
|
IndexSuffix: h.indexSuffix,
|
|
|
|
Ext: h.ext,
|
2024-06-14 21:53:29 +03:00
|
|
|
SourcePath: h.sourcePath,
|
2024-06-09 15:16:38 +03:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|