You've already forked hastebin-ansi
mirror of
https://github.com/armbian/hastebin-ansi.git
synced 2026-01-06 12:30:55 -08:00
114 lines
2.9 KiB
Go
114 lines
2.9 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/armbian/ansi-hastebin/config"
|
|
"github.com/armbian/ansi-hastebin/handler"
|
|
"github.com/armbian/ansi-hastebin/internal/keygenerator"
|
|
"github.com/armbian/ansi-hastebin/internal/storage"
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
"github.com/go-chi/httprate"
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
type Server struct {
|
|
config *config.Config
|
|
storage storage.Storage
|
|
keyGenerator keygenerator.KeyGenerator
|
|
server *http.Server
|
|
mux *chi.Mux
|
|
}
|
|
|
|
func NewServer(config *config.Config, storage storage.Storage, keyGenerator keygenerator.KeyGenerator) *Server {
|
|
mux := chi.NewRouter()
|
|
httpServer := &http.Server{
|
|
Addr: config.Host + ":" + strconv.Itoa(config.Port),
|
|
Handler: mux,
|
|
}
|
|
|
|
return &Server{
|
|
config: config,
|
|
storage: storage,
|
|
keyGenerator: keyGenerator,
|
|
server: httpServer,
|
|
mux: mux,
|
|
}
|
|
}
|
|
|
|
func (s *Server) RegisterRoutes() {
|
|
// Register middlewares
|
|
s.mux.Use(middleware.Logger)
|
|
s.mux.Use(middleware.Recoverer)
|
|
|
|
// Rate limiter
|
|
if s.config.RateLimiting.Enable {
|
|
s.mux.Use(httprate.LimitByRealIP(s.config.RateLimiting.Limit, time.Duration(s.config.RateLimiting.Window)*time.Second))
|
|
}
|
|
|
|
// Register promhttp middleware
|
|
s.mux.Get("/metrics", promhttp.Handler().ServeHTTP)
|
|
|
|
// Register document handler
|
|
documentHandler := handler.NewDocumentHandler(s.config.KeyLength, s.config.MaxLength, s.storage, s.keyGenerator)
|
|
documentHandler.RegisterRoutes(s.mux)
|
|
|
|
// Register health check
|
|
s.mux.Get("/health", func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
// Register static files
|
|
static := os.DirFS("static")
|
|
fileServer := http.FileServer(http.FS(static))
|
|
|
|
s.mux.Get("/*", func(w http.ResponseWriter, r *http.Request) {
|
|
path := strings.TrimPrefix(r.URL.Path, "/")
|
|
if _, err := static.Open(path); err == nil {
|
|
fileServer.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
|
|
// If file does not exist, serve index.html
|
|
index, err := static.Open("index.html")
|
|
if err != nil {
|
|
http.Error(w, "Not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
defer index.Close()
|
|
|
|
if _, err := io.Copy(w, index); err != nil {
|
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
})
|
|
}
|
|
|
|
func (s *Server) Start() {
|
|
log.Info().Str("host", s.config.Host).Int("port", s.config.Port).Msg("Starting server")
|
|
|
|
if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
log.Fatal().Err(err).Msg("Failed to start server")
|
|
}
|
|
}
|
|
|
|
func (s *Server) Shutdown(ctx context.Context) {
|
|
log.Info().Msg("Gracefully shutting down server")
|
|
|
|
if err := s.storage.Close(); err != nil {
|
|
log.Error().Err(err).Msg("Failed to close storage")
|
|
}
|
|
|
|
if err := s.server.Shutdown(ctx); err != nil {
|
|
log.Error().Err(err).Msg("Failed to shutdown server")
|
|
}
|
|
}
|