start scaffolding

This commit is contained in:
2024-04-22 21:53:20 -04:00
parent 6e5af42d93
commit d6dc30bea2
11 changed files with 270 additions and 2 deletions

18
api/auth.go Normal file
View File

@@ -0,0 +1,18 @@
package api
import (
"log/slog"
"net/http"
)
func getLoginHandleFunc(sessions SessionProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
// login html page
}
}
func postLoginHandleFunc(sessions SessionProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
// login html page
}
}

38
api/common.go Normal file
View File

@@ -0,0 +1,38 @@
package api
import (
"log/slog"
"net/http"
)
func versionHandleFunc(log *slog.Logger, version string) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
log.Debug("version handler")
w.WriteHeader(http.StatusOK)
w.Write([]byte(version))
}
}
func staticHandleFunc() func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
}
}
func sessionMiddleware(sessions SessionProvider, log *slog.Logger) func(http.HandlerFunc) http.HandlerFunc {
return func(h http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c, err := r.Cookie("FURTHUR_SESS")
if err != nil {
log.Warn("error loading session")
http.NotFound(w, r)
return
}
if !sessions.Valid(c.Value) {
log.Warn("user provided invalid session")
http.NotFound(w, r)
return
}
h(w, r)
})
}
}

10
api/link.go Normal file
View File

@@ -0,0 +1,10 @@
package api
import (
"log/slog"
"net/http"
)
func linkHandleFunc(links LinkProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}

50
api/manage.go Normal file
View File

@@ -0,0 +1,50 @@
package api
import (
"log/slog"
"net/http"
)
func getManageHandleFunc(log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
func getLinkListHandleFunc(links LinkProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
func getLinkHandleFunc(links LinkProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
func postLinkHandleFunc(links LinkProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
func putLinkHandleFunc(links LinkProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
func deleteLinkHandleFunc(links LinkProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
func getUserListHandleFunc(users UserProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
func getUserHandleFunc(sers UserProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
func postUserHandleFunc(sers UserProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
func putUserHandleFunc(sers UserProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
func deleteUserHandleFunc(sers UserProvider, log *slog.Logger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}

117
api/server.go Normal file
View File

@@ -0,0 +1,117 @@
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()))
}
}
}