mirror of
https://github.com/go-shiori/shiori.git
synced 2025-10-02 17:57:19 +08:00
* chore: use http.NoBody * fix: remove cookie token on logout * fix: remove token cookie on middleware and redirect * fix: frontend sets cookie token if authenticated * refactor: remove session-id, rely on token only * docs: make swagger * fix: redirect * fix: archive route handler * fix: properly unset cookie
190 lines
6.2 KiB
Go
190 lines
6.2 KiB
Go
package http
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
|
|
"github.com/go-shiori/shiori/internal/config"
|
|
"github.com/go-shiori/shiori/internal/dependencies"
|
|
"github.com/go-shiori/shiori/internal/http/handlers"
|
|
api_v1 "github.com/go-shiori/shiori/internal/http/handlers/api/v1"
|
|
"github.com/go-shiori/shiori/internal/http/middleware"
|
|
"github.com/go-shiori/shiori/internal/http/templates"
|
|
"github.com/go-shiori/shiori/internal/model"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type HttpServer struct {
|
|
mux *http.ServeMux
|
|
server *http.Server
|
|
logger *logrus.Logger
|
|
}
|
|
|
|
func (s *HttpServer) Setup(cfg *config.Config, deps *dependencies.Dependencies) (*HttpServer, error) {
|
|
s.mux = http.NewServeMux()
|
|
|
|
if err := templates.SetupTemplates(); err != nil {
|
|
return nil, fmt.Errorf("failed to setup templates: %w", err)
|
|
}
|
|
|
|
globalMiddleware := []model.HttpMiddleware{
|
|
middleware.NewAuthMiddleware(deps),
|
|
middleware.NewRequestIDMiddleware(deps),
|
|
}
|
|
|
|
if cfg.Http.AccessLog {
|
|
globalMiddleware = append(globalMiddleware, middleware.NewLoggingMiddleware())
|
|
}
|
|
|
|
// System routes with logging middleware
|
|
s.mux.HandleFunc("GET /system/liveness", ToHTTPHandler(deps,
|
|
handlers.HandleLiveness,
|
|
globalMiddleware...,
|
|
))
|
|
|
|
// Bookmark routes
|
|
s.mux.HandleFunc("GET /bookmark/{id}/content", ToHTTPHandler(deps, handlers.HandleBookmarkContent, globalMiddleware...))
|
|
s.mux.HandleFunc("GET /bookmark/{id}/archive", ToHTTPHandler(deps, handlers.HandleBookmarkArchive, globalMiddleware...))
|
|
s.mux.HandleFunc("GET /bookmark/{id}/archive/file/{path...}", ToHTTPHandler(deps, handlers.HandleBookmarkArchiveFile, globalMiddleware...))
|
|
s.mux.HandleFunc("GET /bookmark/{id}/thumb", ToHTTPHandler(deps, handlers.HandleBookmarkThumbnail, globalMiddleware...))
|
|
s.mux.HandleFunc("GET /bookmark/{id}/ebook", ToHTTPHandler(deps, handlers.HandleBookmarkEbook, globalMiddleware...))
|
|
|
|
// Add this inside Setup() where other routes are registered
|
|
if cfg.Http.ServeSwagger {
|
|
s.mux.HandleFunc("/swagger/", ToHTTPHandler(deps,
|
|
handlers.HandleSwagger,
|
|
globalMiddleware...,
|
|
))
|
|
}
|
|
|
|
// API v1 routes
|
|
s.mux.HandleFunc("GET /api/v1/system/info", ToHTTPHandler(deps,
|
|
api_v1.HandleSystemInfo,
|
|
globalMiddleware...,
|
|
))
|
|
|
|
// Legacy API routes
|
|
// TODO: Remove this once the legacy API is removed
|
|
legacyHandler := handlers.NewLegacyHandler(deps)
|
|
|
|
s.mux.HandleFunc("GET /api/tags", ToHTTPHandler(deps, legacyHandler.HandleGetTags, globalMiddleware...))
|
|
s.mux.HandleFunc("PUT /api/tags", ToHTTPHandler(deps, legacyHandler.HandleRenameTag, globalMiddleware...))
|
|
s.mux.HandleFunc("GET /api/bookmarks", ToHTTPHandler(deps, legacyHandler.HandleGetBookmarks, globalMiddleware...))
|
|
s.mux.HandleFunc("POST /api/bookmarks", ToHTTPHandler(deps, legacyHandler.HandleInsertBookmark, globalMiddleware...))
|
|
s.mux.HandleFunc("DELETE /api/bookmarks", ToHTTPHandler(deps, legacyHandler.HandleDeleteBookmark, globalMiddleware...))
|
|
s.mux.HandleFunc("PUT /api/bookmarks", ToHTTPHandler(deps, legacyHandler.HandleUpdateBookmark, globalMiddleware...))
|
|
s.mux.HandleFunc("PUT /api/bookmarks/tags", ToHTTPHandler(deps, legacyHandler.HandleUpdateBookmarkTags, globalMiddleware...))
|
|
s.mux.HandleFunc("POST /api/bookmarks/ext", ToHTTPHandler(deps, legacyHandler.HandleInsertViaExtension, globalMiddleware...))
|
|
s.mux.HandleFunc("DELETE /api/bookmarks/ext", ToHTTPHandler(deps, legacyHandler.HandleDeleteViaExtension, globalMiddleware...))
|
|
|
|
// Register routes using standard http handlers
|
|
if cfg.Http.ServeWebUI {
|
|
// Frontend routes
|
|
s.mux.HandleFunc("/", ToHTTPHandler(deps,
|
|
handlers.HandleFrontend,
|
|
globalMiddleware...,
|
|
))
|
|
s.mux.HandleFunc("GET /assets/", ToHTTPHandler(deps,
|
|
handlers.HandleAssets,
|
|
globalMiddleware...,
|
|
))
|
|
}
|
|
|
|
// API v1 routes
|
|
// Auth
|
|
s.mux.HandleFunc("POST /api/v1/auth/login", ToHTTPHandler(deps,
|
|
api_v1.HandleLogin,
|
|
globalMiddleware...,
|
|
))
|
|
s.mux.HandleFunc("POST /api/v1/auth/refresh", ToHTTPHandler(deps,
|
|
api_v1.HandleRefreshToken,
|
|
globalMiddleware...,
|
|
))
|
|
s.mux.HandleFunc("GET /api/v1/auth/me", ToHTTPHandler(deps,
|
|
api_v1.HandleGetMe,
|
|
globalMiddleware...,
|
|
))
|
|
s.mux.HandleFunc("PATCH /api/v1/auth/account", ToHTTPHandler(deps,
|
|
api_v1.HandleUpdateLoggedAccount,
|
|
globalMiddleware...,
|
|
))
|
|
s.mux.HandleFunc("POST /api/v1/auth/logout", ToHTTPHandler(deps,
|
|
api_v1.HandleLogout,
|
|
globalMiddleware...,
|
|
))
|
|
// Accounts
|
|
s.mux.HandleFunc("GET /api/v1/accounts", ToHTTPHandler(deps,
|
|
api_v1.HandleListAccounts,
|
|
globalMiddleware...,
|
|
))
|
|
s.mux.HandleFunc("POST /api/v1/accounts", ToHTTPHandler(deps,
|
|
api_v1.HandleCreateAccount,
|
|
globalMiddleware...,
|
|
))
|
|
s.mux.HandleFunc("DELETE /api/v1/accounts/{id}", ToHTTPHandler(deps,
|
|
api_v1.HandleDeleteAccount,
|
|
globalMiddleware...,
|
|
))
|
|
s.mux.HandleFunc("PATCH /api/v1/accounts/{id}", ToHTTPHandler(deps,
|
|
api_v1.HandleUpdateAccount,
|
|
globalMiddleware...,
|
|
))
|
|
// Tags
|
|
s.mux.HandleFunc("GET /api/v1/tags", ToHTTPHandler(deps,
|
|
api_v1.HandleListTags,
|
|
globalMiddleware...,
|
|
))
|
|
// Bookmarks
|
|
s.mux.HandleFunc("PUT /api/v1/bookmarks/cache", ToHTTPHandler(deps,
|
|
api_v1.HandleUpdateCache,
|
|
globalMiddleware...,
|
|
))
|
|
s.mux.HandleFunc("GET /api/v1/bookmarks/{id}/readable", ToHTTPHandler(deps,
|
|
api_v1.HandleBookmarkReadable,
|
|
globalMiddleware...,
|
|
))
|
|
|
|
s.server = &http.Server{
|
|
Addr: fmt.Sprintf("%s%d", cfg.Http.Address, cfg.Http.Port),
|
|
Handler: s.mux,
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
func (s *HttpServer) Start(_ context.Context) error {
|
|
s.logger.WithField("addr", s.server.Addr).Info("starting http server")
|
|
go func() {
|
|
if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
s.logger.Fatalf("listen and serve error: %s\n", err)
|
|
}
|
|
}()
|
|
return nil
|
|
}
|
|
|
|
func (s *HttpServer) Stop(ctx context.Context) error {
|
|
s.logger.WithField("addr", s.server.Addr).Info("stopping http server")
|
|
return s.server.Shutdown(ctx)
|
|
}
|
|
|
|
func (s *HttpServer) WaitStop(ctx context.Context) {
|
|
signals := make(chan os.Signal, 1)
|
|
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
sig := <-signals
|
|
s.logger.WithField("signal", sig.String()).Info("signal received, shutting down")
|
|
|
|
if err := s.Stop(ctx); err != nil {
|
|
s.logger.WithError(err).Error("error stopping server")
|
|
}
|
|
}
|
|
|
|
func NewHttpServer(logger *logrus.Logger) *HttpServer {
|
|
return &HttpServer{
|
|
logger: logger,
|
|
}
|
|
}
|