Files
kage/pack/serve.go
T
Duc-Tam Nguyen fafa3dfa51 Add the pack package: mirror to zim or self-contained binary
BuildZIM walks a cloned host directory, turns every file into a content
entry with a MIME inferred from its extension, picks a main page, and adds
the standard metadata plus a mainPage redirect. state.json is skipped.
BuildBinary appends the archive to a copy of kage behind a KAGEPCK1 trailer,
and Embedded detects that trailer at startup so the binary serves itself.
Handler maps / to the main page and /path to a content entry, the same
handler the embedded viewer uses.
2026-06-14 20:17:18 +07:00

63 lines
1.5 KiB
Go

package pack
import (
"errors"
"net/http"
"os/exec"
"runtime"
"strings"
"github.com/tamnd/kage/zim"
)
// Handler serves a ZIM archive over HTTP. "/" maps to the archive's main page;
// "/a/b.png" maps to the C/a/b.png content entry. Because the saved HTML's links
// are mirror-relative paths, and those are exactly the C urls, a click in a
// served page hits the right entry with no rewriting. A miss is a plain 404.
func Handler(r *zim.Reader) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
p := strings.TrimPrefix(req.URL.Path, "/")
if p == "" {
blob, err := r.MainPage()
if err != nil {
http.NotFound(w, req)
return
}
serveBlob(w, blob)
return
}
blob, err := r.Get(zim.NamespaceContent, p)
if errors.Is(err, zim.ErrNotFound) {
http.NotFound(w, req)
return
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
serveBlob(w, blob)
})
}
func serveBlob(w http.ResponseWriter, b zim.Blob) {
if b.MimeType != "" {
w.Header().Set("Content-Type", b.MimeType)
}
_, _ = w.Write(b.Data)
}
// OpenInBrowser launches the platform default browser at url. It is best-effort:
// callers print the url regardless and never treat a launch failure as fatal.
func OpenInBrowser(url string) error {
var cmd *exec.Cmd
switch runtime.GOOS {
case "darwin":
cmd = exec.Command("open", url)
case "windows":
cmd = exec.Command("rundll32", "url.dll,FileProtocolHandler", url)
default:
cmd = exec.Command("xdg-open", url)
}
return cmd.Start()
}