refactor: simplified code structure
This commit is contained in:
parent
33b35e6839
commit
e5002d8187
20
cli/serve.go
20
cli/serve.go
|
@ -1,18 +1,20 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/tigorlazuardi/redmage/api"
|
||||
"github.com/tigorlazuardi/redmage/db"
|
||||
"github.com/tigorlazuardi/redmage/db/queries/subreddits"
|
||||
"github.com/tigorlazuardi/redmage/db/queries"
|
||||
"github.com/tigorlazuardi/redmage/pkg/log"
|
||||
"github.com/tigorlazuardi/redmage/server"
|
||||
"github.com/tigorlazuardi/redmage/server/routes/api"
|
||||
"github.com/tigorlazuardi/redmage/server/routes/www"
|
||||
)
|
||||
|
||||
var PublicDir fs.FS = os.DirFS("public")
|
||||
|
||||
var serveCmd = &cobra.Command{
|
||||
Use: "serve",
|
||||
Short: "Starts the HTTP Server",
|
||||
|
@ -24,18 +26,14 @@ var serveCmd = &cobra.Command{
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
subreddits := subreddits.New(db)
|
||||
queries := queries.New(db)
|
||||
|
||||
api := &api.API{
|
||||
Subreddits: subreddits,
|
||||
Config: cfg,
|
||||
Queries: queries,
|
||||
DB: db,
|
||||
}
|
||||
|
||||
www := &www.WWW{
|
||||
Subreddits: subreddits,
|
||||
Config: cfg,
|
||||
}
|
||||
server := server.New(cfg, api, www)
|
||||
server := server.New(cfg, api, PublicDir)
|
||||
|
||||
exit := make(chan struct{}, 1)
|
||||
|
||||
|
|
3
main.go
3
main.go
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/joho/godotenv"
|
||||
"github.com/tigorlazuardi/redmage/cli"
|
||||
"github.com/tigorlazuardi/redmage/db"
|
||||
"github.com/tigorlazuardi/redmage/server/routes/www"
|
||||
)
|
||||
|
||||
//go:embed db/migrations/*.sql
|
||||
|
@ -23,7 +22,7 @@ func main() {
|
|||
_ = godotenv.Load()
|
||||
db.Migrations = Migrations
|
||||
var err error
|
||||
www.PublicFS, err = fs.Sub(PublicFS, "public")
|
||||
cli.PublicDir, err = fs.Sub(PublicFS, "public")
|
||||
if err != nil {
|
||||
panic(errors.New("failed to create sub filesystem"))
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
chimiddleware "github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/tigorlazuardi/redmage/config"
|
||||
"github.com/tigorlazuardi/redmage/db/queries/subreddits"
|
||||
"github.com/tigorlazuardi/redmage/server/routes/middleware"
|
||||
)
|
||||
|
||||
type API struct {
|
||||
Subreddits *subreddits.Queries
|
||||
Config *config.Config
|
||||
}
|
||||
|
||||
func (api *API) Register(router chi.Router) {
|
||||
router.Use(chimiddleware.RequestID)
|
||||
router.Get("/", HealthCheck)
|
||||
router.Get("/health", HealthCheck)
|
||||
router.Route("/subreddits", func(r chi.Router) {
|
||||
r.Use(chimiddleware.RequestLogger(middleware.ChiLogger{}))
|
||||
r.Get("/", api.ListSubreddits)
|
||||
})
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func HealthCheck(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.Header().Add("Content-Type", "application/json")
|
||||
_, _ = rw.Write([]byte(`{"status":"ok"}`))
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/tigorlazuardi/redmage/db/queries/subreddits"
|
||||
"github.com/tigorlazuardi/redmage/pkg/log"
|
||||
)
|
||||
|
||||
func (api *API) ListSubreddits(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.Header().Add("Content-Type", "application/json")
|
||||
subs, err := api.Subreddits.ListSubreddits(r.Context(), parseListSubredditsQuery(r))
|
||||
if err != nil {
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
msg := fmt.Sprintf("failed to list subreddits: %s", err)
|
||||
_ = json.NewEncoder(rw).Encode(map[string]string{"error": msg})
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(rw).Encode(subs); err != nil {
|
||||
log.New(r.Context()).Err(err).Error("failed to list subreddits")
|
||||
}
|
||||
}
|
||||
|
||||
func parseListSubredditsQuery(r *http.Request) subreddits.ListSubredditsParams {
|
||||
params := subreddits.ListSubredditsParams{}
|
||||
params.Limit, _ = strconv.ParseInt(r.URL.Query().Get("limit"), 10, 64)
|
||||
params.Offset, _ = strconv.ParseInt(r.URL.Query().Get("offset"), 10, 64)
|
||||
|
||||
if params.Limit < 1 {
|
||||
params.Limit = 10
|
||||
} else if params.Limit > 100 {
|
||||
params.Limit = 100
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
9
server/routes/health_check.go
Normal file
9
server/routes/health_check.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (routes *Routes) HealthCheck(rw http.ResponseWriter, req *http.Request) {
|
||||
_, _ = rw.Write([]byte{})
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package www
|
||||
package routes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/tigorlazuardi/redmage/pkg/log"
|
||||
)
|
||||
|
||||
func (www *WWW) CreateHotReloadRoute() http.HandlerFunc {
|
||||
func (routes *Routes) CreateHotReloadRoute() http.HandlerFunc {
|
||||
var mu sync.Mutex
|
||||
knownClients := make(map[string]chan struct{})
|
||||
firstTime := make(chan struct{}, 1)
|
17
server/routes/page_home.go
Normal file
17
server/routes/page_home.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/tigorlazuardi/redmage/pkg/log"
|
||||
"github.com/tigorlazuardi/redmage/views"
|
||||
"github.com/tigorlazuardi/redmage/views/homeview"
|
||||
)
|
||||
|
||||
func (routes *Routes) PageHome(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
vc := views.NewContext(routes.Config, r)
|
||||
if err := homeview.Home(vc).Render(ctx, rw); err != nil {
|
||||
log.New(ctx).Err(err).Error("failed to render home view")
|
||||
}
|
||||
}
|
45
server/routes/routes.go
Normal file
45
server/routes/routes.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
chimiddleware "github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/tigorlazuardi/redmage/api"
|
||||
"github.com/tigorlazuardi/redmage/config"
|
||||
"github.com/tigorlazuardi/redmage/server/routes/middleware"
|
||||
)
|
||||
|
||||
type Routes struct {
|
||||
API *api.API
|
||||
Config *config.Config
|
||||
PublicDir fs.FS
|
||||
}
|
||||
|
||||
func (routes *Routes) Register(router chi.Router) {
|
||||
router.HandleFunc("/ping", routes.HealthCheck)
|
||||
router.HandleFunc("/health", routes.HealthCheck)
|
||||
if routes.Config.Bool("http.hotreload") {
|
||||
router.Get("/hot_reload", routes.CreateHotReloadRoute())
|
||||
}
|
||||
|
||||
router.Group(routes.registerWWWRoutes)
|
||||
router.Route("/api/v1", routes.registerV1APIRoutes)
|
||||
}
|
||||
|
||||
func (routes *Routes) registerV1APIRoutes(router chi.Router) {
|
||||
router.Use(chimiddleware.RequestLogger(middleware.ChiLogger{}))
|
||||
router.Use(chimiddleware.SetHeader("Content-Type", "application/json"))
|
||||
|
||||
router.Get("/subreddits", routes.SubredditsListAPI)
|
||||
}
|
||||
|
||||
func (routes *Routes) registerWWWRoutes(router chi.Router) {
|
||||
router.Mount("/public", http.StripPrefix("/public", http.FileServer(http.FS(routes.PublicDir))))
|
||||
|
||||
router.Group(func(r chi.Router) {
|
||||
r.Use(chimiddleware.RequestLogger(middleware.ChiLogger{}))
|
||||
r.Get("/", routes.PageHome)
|
||||
})
|
||||
}
|
41
server/routes/subreddit_list.go
Normal file
41
server/routes/subreddit_list.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/tigorlazuardi/redmage/api"
|
||||
"github.com/tigorlazuardi/redmage/pkg/log"
|
||||
)
|
||||
|
||||
func (r *Routes) SubredditsListAPI(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx := req.Context()
|
||||
params := parseSubredditListQuery(req)
|
||||
|
||||
result, err := r.API.ListSubreddits(ctx, params)
|
||||
if err != nil {
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
_ = json.NewEncoder(rw).Encode(map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(rw).Encode(result); err != nil {
|
||||
log.New(ctx).Err(err).Error("failed to encode subreddits into json")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Routes) SubredditsListPage(rw http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
func parseSubredditListQuery(req *http.Request) (params api.ListSubredditsParams) {
|
||||
params.Name = req.FormValue("name")
|
||||
params.Limit, _ = strconv.ParseInt(req.FormValue("limit"), 10, 64)
|
||||
if params.Limit < 1 {
|
||||
params.Limit = 10
|
||||
} else if params.Limit > 100 {
|
||||
params.Limit = 100
|
||||
}
|
||||
params.Offset, _ = strconv.ParseInt(req.FormValue("offset"), 10, 64)
|
||||
return params
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package www
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/tigorlazuardi/redmage/views"
|
||||
"github.com/tigorlazuardi/redmage/views/homeview"
|
||||
)
|
||||
|
||||
func (www *WWW) Home(rw http.ResponseWriter, r *http.Request) {
|
||||
_ = homeview.Home(views.NewContext(www.Config, r)).Render(r.Context(), rw)
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package www
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
chimiddleware "github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/tigorlazuardi/redmage/config"
|
||||
"github.com/tigorlazuardi/redmage/db/queries/subreddits"
|
||||
"github.com/tigorlazuardi/redmage/pkg/log"
|
||||
"github.com/tigorlazuardi/redmage/server/routes/middleware"
|
||||
)
|
||||
|
||||
var PublicFS = os.DirFS("public")
|
||||
|
||||
type WWW struct {
|
||||
Subreddits *subreddits.Queries
|
||||
Config *config.Config
|
||||
}
|
||||
|
||||
func (www *WWW) Register(router chi.Router) {
|
||||
router.Use(chimiddleware.RealIP)
|
||||
router.
|
||||
With(chimiddleware.RequestLogger(middleware.ChiSimpleLogger{})).
|
||||
Mount("/public", http.StripPrefix("/public", http.FileServer(http.FS(PublicFS))))
|
||||
|
||||
if www.Config.Bool("http.hotreload") {
|
||||
log.New(context.Background()).Debug("enabled hot reload")
|
||||
router.
|
||||
With(chimiddleware.RequestLogger(middleware.ChiSimpleLogger{})).
|
||||
Get("/hot_reload", www.CreateHotReloadRoute())
|
||||
}
|
||||
|
||||
router.Group(func(r chi.Router) {
|
||||
r.Use(chimiddleware.RequestID)
|
||||
r.Use(chimiddleware.RequestLogger(middleware.ChiLogger{}))
|
||||
r.Use(chimiddleware.SetHeader("Content-Type", "text/html; utf-8"))
|
||||
r.Get("/", www.Home)
|
||||
})
|
||||
}
|
|
@ -3,20 +3,22 @@ package server
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/tigorlazuardi/redmage/api"
|
||||
"github.com/tigorlazuardi/redmage/config"
|
||||
"github.com/tigorlazuardi/redmage/pkg/caller"
|
||||
"github.com/tigorlazuardi/redmage/pkg/errs"
|
||||
"github.com/tigorlazuardi/redmage/pkg/log"
|
||||
"github.com/tigorlazuardi/redmage/server/routes/api"
|
||||
"github.com/tigorlazuardi/redmage/server/routes/www"
|
||||
"github.com/tigorlazuardi/redmage/server/routes"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
server *http.Server
|
||||
config *config.Config
|
||||
PublicDir fs.FS
|
||||
}
|
||||
|
||||
func (srv *Server) Start(exit <-chan struct{}) error {
|
||||
|
@ -41,11 +43,16 @@ func (srv *Server) Start(exit <-chan struct{}) error {
|
|||
}
|
||||
}
|
||||
|
||||
func New(cfg *config.Config, api *api.API, www *www.WWW) *Server {
|
||||
func New(cfg *config.Config, api *api.API, publicDir fs.FS) *Server {
|
||||
router := chi.NewRouter()
|
||||
|
||||
router.Route("/api", api.Register)
|
||||
router.Route("/", www.Register)
|
||||
routes := routes.Routes{
|
||||
API: api,
|
||||
Config: cfg,
|
||||
PublicDir: publicDir,
|
||||
}
|
||||
|
||||
routes.Register(router)
|
||||
|
||||
server := &http.Server{
|
||||
Handler: router,
|
||||
|
|
Loading…
Reference in a new issue