118 lines
3.1 KiB
Go
118 lines
3.1 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
|
|
"git.yetaga.in/alazyreader/going-further/storage"
|
|
)
|
|
|
|
type LinkProvider interface {
|
|
Link(key string) *url.URL
|
|
List() []string
|
|
Details(key string) storage.Link
|
|
}
|
|
|
|
type SessionProvider interface {
|
|
Login(username string, password string) (string, bool) // session token, valid
|
|
Valid(token string) bool
|
|
User(token string) string // token -> username
|
|
}
|
|
|
|
type UserProvider interface {
|
|
List() []string // usernames
|
|
Add(username string, password string) error
|
|
Update(username string, password string) error
|
|
Remove(username string) error
|
|
}
|
|
|
|
type shutdown struct {
|
|
wait int
|
|
timeout int
|
|
}
|
|
|
|
type Server struct {
|
|
host string
|
|
port string
|
|
version string
|
|
|
|
users UserProvider
|
|
sessions SessionProvider
|
|
links LinkProvider
|
|
|
|
http *http.Server
|
|
waits shutdown
|
|
|
|
log *slog.Logger
|
|
}
|
|
|
|
func NewServer(logger *slog.Logger, port string, version string) *Server {
|
|
return &Server{
|
|
log: logger,
|
|
port: port,
|
|
version: version,
|
|
waits: shutdown{
|
|
wait: 10,
|
|
timeout: 10,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Setup returns start and stop functions for the http service
|
|
func (s *Server) Setup() (func(), func()) {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("GET /version", versionHandleFunc(s.log, s.version))
|
|
|
|
mux.HandleFunc("GET /login", getLoginHandleFunc(s.sessions, s.log))
|
|
mux.HandleFunc("POST /login", postLoginHandleFunc(s.sessions, s.log))
|
|
|
|
mux.HandleFunc("GET /manage", getManageHandleFunc(s.log))
|
|
|
|
mux.HandleFunc("GET /manage/links", getLinkListHandleFunc(s.links, s.log))
|
|
mux.HandleFunc("GET /manage/links/{name}", getLinkHandleFunc(s.links, s.log))
|
|
mux.HandleFunc("POST /manage/links", postLinkHandleFunc(s.links, s.log))
|
|
mux.HandleFunc("PUT /manage/links/{name}", putLinkHandleFunc(s.links, s.log))
|
|
mux.HandleFunc("DELETE /manage/links/{name}", deleteLinkHandleFunc(s.links, s.log))
|
|
|
|
mux.HandleFunc("GET /manage/users", getUserListHandleFunc(s.users, s.log))
|
|
mux.HandleFunc("GET /manage/users/{name}", getUserHandleFunc(s.users, s.log))
|
|
mux.HandleFunc("POST /manage/users", postUserHandleFunc(s.users, s.log))
|
|
mux.HandleFunc("PUT /manage/users/{name}", putUserHandleFunc(s.users, s.log))
|
|
mux.HandleFunc("DELETE /manage/users/{name}", deleteUserHandleFunc(s.users, s.log))
|
|
|
|
mux.HandleFunc("GET /static/", staticHandleFunc())
|
|
|
|
mux.HandleFunc("GET /", linkHandleFunc(s.links, s.log))
|
|
|
|
s.http = &http.Server{
|
|
Addr: net.JoinHostPort(s.host, s.port),
|
|
Handler: mux,
|
|
}
|
|
|
|
return s.start(), s.stop()
|
|
}
|
|
|
|
func (s *Server) start() func() {
|
|
return func() {
|
|
s.log.Info("server startup", slog.String("addr", s.http.Addr))
|
|
if err := s.http.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
s.log.Error("error listening and serving", slog.String("error", err.Error()))
|
|
}
|
|
}
|
|
}
|
|
func (s *Server) stop() func() {
|
|
return func() {
|
|
s.log.Info("server shutdown")
|
|
time.Sleep(time.Duration(s.waits.wait) * time.Second)
|
|
shutdownCtx, cancel := context.WithTimeout(context.Background(), time.Duration(s.waits.timeout)*time.Second)
|
|
defer cancel()
|
|
if err := s.http.Shutdown(shutdownCtx); err != nil {
|
|
s.log.Error("error shutting down http server", slog.String("error", err.Error()))
|
|
}
|
|
}
|
|
}
|