start scaffolding
This commit is contained in:
		
							
								
								
									
										18
									
								
								api/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								api/auth.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										38
									
								
								api/common.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										10
									
								
								api/link.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										50
									
								
								api/manage.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										117
									
								
								api/server.go
									
									
									
									
									
										Normal 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()))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user