118 lines
2.6 KiB
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
|
|
}
|