goveal/internal/app/server/http_server.go

118 lines
2.6 KiB
Go

package server
import (
"fmt"
"io/fs"
"net"
"net/http"
"os"
"github.com/baez90/goveal/assets"
"github.com/baez90/goveal/internal/app/rendering"
"github.com/baez90/goveal/internal/app/routing"
"github.com/baez90/goveal/internal/encoding"
)
const (
markdownFilePath = "/content.md"
)
type (
Config struct {
Host string
Port uint16
MarkdownPath string
RevealParams *rendering.RevealParams
}
HTTPServer struct {
listener net.Listener
handler http.Handler
}
)
func (srv HTTPServer) Serve() error {
return http.Serve(srv.listener, srv.handler)
}
func (srv HTTPServer) ListenAddress() string {
return srv.listener.Addr().String()
}
func NewHTTPServer(config Config) (srv *HTTPServer, err error) {
noCacheFiles := append(config.RevealParams.FilesToMonitor, markdownFilePath)
if err := detectMarkdownFileEnding(config.MarkdownPath, config.RevealParams); err != nil {
return nil, err
}
router := &routing.RegexpRouter{}
var tmplRenderer rendering.RevealRenderer
if tmplRenderer, err = rendering.NewRevealRenderer(config.RevealParams); err != nil {
err = fmt.Errorf("failed to initialize reveal renderer %w", err)
return
}
// language=regexp
if err = router.AddRule(`^(/(index.html(l)?)?)?$`, tmplRenderer); err != nil {
return
}
var mdFS http.FileSystem
if mdFS, err = routing.NewMarkdownFS(config.MarkdownPath); err != nil {
err = fmt.Errorf("failed to initialize markdown file handler %w", err)
return
}
var revealFS, webFS fs.FS
if revealFS, err = fs.Sub(assets.Assets, "reveal"); err != nil {
return nil, err
}
if webFS, err = fs.Sub(assets.Assets, "web"); err != nil {
return nil, err
}
layeredFS := routing.NewLayeredFileSystem(http.FS(revealFS), http.FS(webFS), http.Dir("."), mdFS)
// language=regexp
if err = router.AddRule(`^(?i)/hash/(md5|sha1|sha2)/.*`, NewHashHandler(layeredFS)); err != nil {
return
}
// language=regexp
if err = router.AddRule("^/.*\\.md$", http.FileServer(mdFS)); err != nil {
return
}
// language=regexp
if err = router.AddRule("/.+", http.FileServer(layeredFS)); err != nil {
return
}
hostPort := fmt.Sprintf("%s:%d", config.Host, config.Port)
srv = &HTTPServer{
handler: routing.NoCache(router, noCacheFiles),
}
if srv.listener, err = net.Listen("tcp", hostPort); err != nil {
return
}
return
}
func detectMarkdownFileEnding(filePath string, params *rendering.RevealParams) error {
f, err := os.Open(filePath)
if err != nil {
return err
}
defer func() {
_ = f.Close()
}()
if le, err := encoding.Detect(f); err != nil {
return err
} else {
params.LineEnding = le
}
return nil
}