190 lines
3.6 KiB
Go
190 lines
3.6 KiB
Go
|
package server
|
||
|
|
||
|
import (
|
||
|
//"github.com/d5/tengo/v2"
|
||
|
"surdeus.su/util/tpp/mdx"
|
||
|
//"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)
|
||
|
urlExt := path.Ext(urlPath)
|
||
|
|
||
|
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?
|
||
|
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)
|
||
|
}
|