forked from Botanical/BotanJS
115 lines
2.6 KiB
Go
115 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/tgckpg/resolver-go/internal/closure"
|
|
"github.com/tgckpg/resolver-go/internal/generated"
|
|
"github.com/tgckpg/resolver-go/internal/resolver"
|
|
)
|
|
|
|
func main() {
|
|
addr := flag.String("addr", ":8080", "listen address")
|
|
src := flag.String("src", "./src", "BotanJS source root")
|
|
flag.Parse()
|
|
|
|
r, err := resolver.New(*src, generated.ClassMap)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
h := handler{
|
|
r: r,
|
|
closure: closure.NewCompileCache(2),
|
|
}
|
|
http.HandleFunc("/", h.index)
|
|
log.Printf("botan-api listening on %s", *addr)
|
|
log.Fatal(http.ListenAndServe(*addr, nil))
|
|
}
|
|
|
|
type handler struct {
|
|
r *resolver.Resolver
|
|
closure *closure.CompileCache
|
|
}
|
|
|
|
func (h handler) index(w http.ResponseWriter, req *http.Request) {
|
|
path := strings.Trim(req.URL.Path, "/")
|
|
if path == "" {
|
|
_, _ = w.Write([]byte("BotanJS Go resolver API\n"))
|
|
return
|
|
}
|
|
parts := strings.SplitN(path, "/", 2)
|
|
modeText := parts[0]
|
|
code := ""
|
|
if len(parts) == 2 {
|
|
code = parts[1]
|
|
} else {
|
|
code = req.URL.Query().Get("p")
|
|
}
|
|
if code == "" {
|
|
http.Error(w, "missing request payload", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
outMode := resolver.ModeJS
|
|
if strings.HasSuffix(modeText, "css") {
|
|
outMode = resolver.ModeCSS
|
|
} else if !strings.HasSuffix(modeText, "js") {
|
|
http.Error(w, "invalid mode", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
res, err := h.r.ResolveRequest(code, outMode, nil)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
if outMode == resolver.ModeJS {
|
|
if compiled, ok := h.closure.Get(res.Hash); ok {
|
|
w.Header().Set("Content-Type", "application/javascript")
|
|
w.Header().Set("X-Botan-Compiled", "hit")
|
|
w.Write(compiled)
|
|
return
|
|
}
|
|
|
|
jsExterns, err := h.r.GetExterns(generated.Externs)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
h.closure.Enqueue(closure.CompileJob{
|
|
Hash: res.Hash,
|
|
Mode: "js",
|
|
ExternSources: jsExterns,
|
|
JSSources: []closure.SourceInput{
|
|
{
|
|
Name: "botanjs-" + res.Hash + ".js",
|
|
Source: string(res.Content),
|
|
},
|
|
},
|
|
Defines: map[string]any{
|
|
"DEBUG": false,
|
|
},
|
|
})
|
|
}
|
|
|
|
// Compatibility flags:
|
|
// rjs/rcss/ojs/ocss => content
|
|
// hjs/hcss => hash filename only
|
|
// js/css => currently content; cluster compiler can switch this later.
|
|
if strings.HasPrefix(modeText, "h") {
|
|
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
_, _ = w.Write([]byte(res.Hash))
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", res.ContentType)
|
|
w.Header().Set("X-Botan-Compiled", "miss")
|
|
|
|
_, _ = w.Write(res.Content)
|
|
}
|