137 lines
3.3 KiB
Go
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 = ®isterNotFoundHandler{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 = ¬FoundHandler{s}
|
|
if s.Config.WebDav {
|
|
fs := authdav.NewWriteOnlyOnceFileSystem(webdav.Dir(s.Config.DataDir))
|
|
fs.Filters = []authdav.Filter{authdav.NewMacOSFilter()}
|
|
h := authdav.NewWebdavBasicAuth(core.WebDavPrefix, fs, 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))
|
|
}
|
|
}
|