docstore/pkg/server/server.go
2021-11-05 22:10:52 +01:00

137 lines
3.3 KiB
Go

// Copyright (C) 2021 Marius Schellenberger
package server
import (
"bytes"
"context"
"embed"
"errors"
"git.giftfish.de/ston1th/authdav"
"git.giftfish.de/ston1th/docstore/pkg/core"
"git.giftfish.de/ston1th/docstore/pkg/db"
"git.giftfish.de/ston1th/docstore/pkg/fs"
"git.giftfish.de/ston1th/docstore/pkg/log"
"git.giftfish.de/ston1th/docstore/pkg/scan"
"git.giftfish.de/ston1th/godrop/v2"
"git.giftfish.de/ston1th/jwt/v3"
"github.com/gorilla/mux"
"golang.org/x/net/webdav"
"html/template"
"net"
"net/http"
"time"
)
const (
cookieName = "docstore_session"
)
type HTTPServer struct {
Config *core.Config
listener net.Listener
srv *http.Server
handler http.Handler
DB *db.DB
JWT *jwt.JWT
Scanner *scan.Scanner
FS *fs.Filesystem
Log *log.ScanLog
templ map[string]*template.Template
res map[string][]byte
}
func NewHTTPServer(cfg *core.Config, l net.Listener, s *scan.Scanner) (srv *HTTPServer) {
srv = &HTTPServer{
Config: cfg,
listener: l,
Scanner: s,
Log: log.NewScanLog(0),
}
srv.loadTemplates()
srv.srv = &http.Server{}
return
}
func (s *HTTPServer) Start() (err error) {
s.FS, err = fs.NewFilesystem(s.Config.DataDir)
if err != nil {
return errors.New("fs: " + err.Error())
}
s.DB, err = db.New(s.Config)
if err != nil {
return errors.New("db: " + err.Error())
}
err = godrop.UnveilBlock()
if err != nil {
return
}
if s.Config.Secret != "" {
s.JWT, err = jwt.New(jwt.DefaultExpiry, s.DB, bytes.NewBufferString(s.Config.Secret))
} else {
s.JWT, err = jwt.New(jwt.DefaultExpiry, s.DB, nil)
}
if err != nil {
return errors.New("server: " + err.Error())
}
s.handler = s.buildRoutes()
if !s.DB.UserExists() {
log.Debug("server: starting register handler")
s.srv.Handler = s.register()
} else {
s.srv.Handler = s.handler
}
go func() {
log.Println(s.srv.Serve(s.listener))
}()
return
}
func (s *HTTPServer) Stop() error {
s.DB.Close()
s.JWT.Stop()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
return s.srv.Shutdown(ctx)
}
func (s *HTTPServer) register() http.Handler {
r := mux.NewRouter()
r.NotFoundHandler = &registerNotFoundHandler{s}
r.Handle("/static/{file}", http.StripPrefix("/", http.FileServer(http.FS(static))))
for _, v := range registerRoutes {
r.HandleFunc(v.Path, s.contextWrapper(v.Handler)).Methods(v.Methods...)
}
return r
}
//go:embed static/*
var static embed.FS
func (s *HTTPServer) buildRoutes() http.Handler {
r := mux.NewRouter()
r.NotFoundHandler = &notFoundHandler{s}
if s.Config.WebDav {
dav := authdav.NewWriteOnlyOnceFileSystem(webdav.Dir(s.Config.DataDir))
dav.Filters = []authdav.Filter{authdav.NewMacOSFilter()}
h := authdav.NewWebdavBasicAuth(core.WebDavPrefix, dav, nil, webdavLogger, s.DB, "DocStore WebDav")
r.PathPrefix(core.WebDavPrefix).Handler(h)
}
r.Handle("/static/{file}", http.StripPrefix("/", http.FileServer(http.FS(static))))
for _, v := range routes {
r.HandleFunc(v.Path, s.contextWrapper(v.Handler)).Methods(v.Methods...)
}
for _, v := range prefixRoutes {
r.PathPrefix(v.Path).HandlerFunc(s.contextWrapper(v.Handler)).Methods(v.Methods...)
}
return r
}
func (s *HTTPServer) contextWrapper(h ctxHandler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
h(newContext(w, r, s))
}
}