DEVELOPMENT ENVIRONMENT

~liljamo/felu

518adb1afd74f88f3ee7138d4cfb07272e1a5b1a — Jonni Liljamo 1 year, 1 month ago cecbccc
refactor: backend -> api, move routers
M cmd/felu/main.go => cmd/felu/main.go +7 -100
@@ 7,7 7,6 @@
package main

import (
	"fmt"
	"log"
	"net/http"
	"strconv"


@@ 16,11 15,8 @@ import (
	"git.src.quest/~skye/felu-ddns/internal/config"
	"git.src.quest/~skye/felu-ddns/internal/db"
	"git.src.quest/~skye/felu-ddns/internal/dns"
	"git.src.quest/~skye/felu-ddns/internal/handlers"
	"git.src.quest/~skye/felu-ddns/internal/middlewares"
	"git.src.quest/~skye/felu-ddns/internal/renderer"
	"git.src.quest/~skye/felu-ddns/internal/routers"
	"github.com/alexedwards/scs/v2"
	"github.com/gin-gonic/gin"
	"golang.org/x/sync/errgroup"
)



@@ 31,95 27,6 @@ var (
	sessionManager *scs.SessionManager
)

func ginLogFormat(param gin.LogFormatterParams, router string) string {
	var statusColor, methodColor, resetColor string
	if param.IsOutputColor() {
		statusColor = param.StatusCodeColor()
		methodColor = param.MethodColor()
		resetColor = param.ResetColor()
	}

	if param.Latency > time.Minute {
		param.Latency = param.Latency.Truncate(time.Second)
	}
	return fmt.Sprintf("[GIN] [felu/%-8s] | %v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n%s",
		router,
		param.TimeStamp.Format("2006/01/02 - 15:04:05"),
		statusColor, param.StatusCode, resetColor,
		param.Latency,
		param.ClientIP,
		methodColor, param.Method, resetColor,
		param.Path,
		param.ErrorMessage,
	)
}

func setupFrontendRouter() *gin.Engine {
	r := gin.New()
	r.Use(gin.Recovery())
	r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
		return ginLogFormat(param, "frontend")
	}))
	r.Static("/static", "./static")
	r.HTMLRender = &renderer.TemplRender{}

	r.GET("/", handlers.Index())
	r.GET("/login", middlewares.SessionExists(sessionManager), handlers.Login())

	auth := r.Group("/auth")
	{
		auth.POST("/login", handlers.AuthLogin(sessionManager))
	}

	// routes for the actual application frontend
	manage := r.Group("/manage", middlewares.SessionExists(sessionManager))
	{
		manage.GET("/", handlers.Manage())
		manage.GET("/settings", handlers.ManageSettings())

		manage.POST("/domains", handlers.PostDomain())
		manage.PATCH("/domains/:id") // TODO:
		manage.DELETE("/domains/:id", handlers.DeleteDomain())

		manage.GET("/partials/domains", handlers.ManagePartialDomains())
	}
	manageAdmin := r.Group("/manage/admin",
		middlewares.SessionExists(sessionManager), middlewares.AdminOnly())
	{
		manageAdmin.GET("/", handlers.ManageAdmin())
		manageAdmin.GET("/users", handlers.ManageAdminUsers())
		manageAdmin.GET("/domains", handlers.ManageAdminDomains())

		manageAdmin.POST("/users", handlers.PostUser())

		manageAdmin.GET("/partials/users_list", handlers.AdminPartialUsersList())
	}

	return r
}

func setupBackendRouter() *gin.Engine {
	r := gin.New()
	r.Use(gin.Recovery())
	r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
		return ginLogFormat(param, "backend")
	}))

	r.GET("/", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"status": "success",
		})
	})

	r.GET("/version", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"version": version,
		})
	})

	return r
}

func main() {
	log.Print("[felu] Starting up...")



@@ 138,14 45,14 @@ func main() {

	frontend := &http.Server{
		Addr: config.FeluConfig.FrontendBindAddr,
		Handler: sessionManager.LoadAndSave(setupFrontendRouter()),
		Handler: sessionManager.LoadAndSave(routers.SetupFrontendRouter(sessionManager)),
		ReadTimeout: 5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	backend := &http.Server{
		Addr: config.FeluConfig.BackendBindAddr,
		Handler: setupBackendRouter(),
	api := &http.Server{
		Addr: config.FeluConfig.APIBindAddr,
		Handler: routers.SetupAPIRouter(version),
		ReadTimeout: 5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}


@@ 155,9 62,9 @@ func main() {
		return frontend.ListenAndServe()
	})

	log.Printf("[felu] Serving backend at '%s'", config.FeluConfig.BackendBindAddr)
	log.Printf("[felu] Serving api at '%s'", config.FeluConfig.APIBindAddr)
	g.Go(func() error {
		return backend.ListenAndServe()
		return api.ListenAndServe()
	})

	dnsIP := config.FeluConfig.DNSBindIP

M internal/config/config.go => internal/config/config.go +2 -2
@@ 23,7 23,7 @@ type config struct {

	FrontendBindAddr string

	BackendBindAddr string
	APIBindAddr string

	DNSBindIP   string
	DNSBindPort int32


@@ 42,7 42,7 @@ func InitConfig() {

		FrontendBindAddr: util.LoadEnvStr("FELU_FRONTEND_BIND_ADDR", "0.0.0.0:8080"),

		BackendBindAddr: util.LoadEnvStr("FELU_BACKEND_BIND_ADDR", "0.0.0.0:8081"),
		APIBindAddr: util.LoadEnvStr("FELU_API_BIND_ADDR", "0.0.0.0:8081"),

		DNSBindIP: util.LoadEnvStr("FELU_DNS_BIND_IP", "0.0.0.0"),
		DNSBindPort: util.LoadEnvInt32("FELU_DNS_BIND_PORT", 53),

A internal/log/ginformat.go => internal/log/ginformat.go +37 -0
@@ 0,0 1,37 @@
/*
 * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
 *
 * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for
 * more information.
 */
package log

import (
	"fmt"
	"time"

	"github.com/gin-gonic/gin"
)

func GinFormat(param gin.LogFormatterParams, router string) string {
	var statusColor, methodColor, resetColor string
	if param.IsOutputColor() {
		statusColor = param.StatusCodeColor()
		methodColor = param.MethodColor()
		resetColor = param.ResetColor()
	}

	if param.Latency > time.Minute {
		param.Latency = param.Latency.Truncate(time.Second)
	}
	return fmt.Sprintf("[GIN] [felu/%-8s] | %v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n%s",
		router,
		param.TimeStamp.Format("2006/01/02 - 15:04:05"),
		statusColor, param.StatusCode, resetColor,
		param.Latency,
		param.ClientIP,
		methodColor, param.Method, resetColor,
		param.Path,
		param.ErrorMessage,
	)
}

A internal/routers/api.go => internal/routers/api.go +36 -0
@@ 0,0 1,36 @@
/*
 * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
 *
 * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for
 * more information.
 */
package routers

import (
	"net/http"

	"git.src.quest/~skye/felu-ddns/internal/log"
	"github.com/gin-gonic/gin"
)

func SetupAPIRouter(version string) *gin.Engine {
	r := gin.New()
	r.Use(gin.Recovery())
	r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
		return log.GinFormat(param, "api")
	}))

	r.GET("/", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"status": "success",
		})
	})

	r.GET("/version", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"version": version,
		})
	})

	return r
}

A internal/routers/frontend.go => internal/routers/frontend.go +60 -0
@@ 0,0 1,60 @@
/*
 * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
 *
 * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for
 * more information.
 */
package routers

import (
	"git.src.quest/~skye/felu-ddns/internal/handlers"
	"git.src.quest/~skye/felu-ddns/internal/log"
	"git.src.quest/~skye/felu-ddns/internal/middlewares"
	"git.src.quest/~skye/felu-ddns/internal/renderer"
	"github.com/alexedwards/scs/v2"
	"github.com/gin-gonic/gin"
)

func SetupFrontendRouter(sm *scs.SessionManager) *gin.Engine {
	r := gin.New()
	r.Use(gin.Recovery())
	r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
		return log.GinFormat(param, "frontend")
	}))
	r.Static("/static", "./static")
	r.HTMLRender = &renderer.TemplRender{}

	r.GET("/", handlers.Index())
	r.GET("/login", middlewares.SessionExists(sm), handlers.Login())

	auth := r.Group("/auth")
	{
		auth.POST("/login", handlers.AuthLogin(sm))
	}

	// routes for the actual application frontend
	manage := r.Group("/manage", middlewares.SessionExists(sm))
	{
		manage.GET("/", handlers.Manage())
		manage.GET("/settings", handlers.ManageSettings())

		manage.POST("/domains", handlers.PostDomain())
		manage.PATCH("/domains/:id") // TODO:
		manage.DELETE("/domains/:id", handlers.DeleteDomain())

		manage.GET("/partials/domains", handlers.ManagePartialDomains())
	}
	manageAdmin := r.Group("/manage/admin",
		middlewares.SessionExists(sm), middlewares.AdminOnly())
	{
		manageAdmin.GET("/", handlers.ManageAdmin())
		manageAdmin.GET("/users", handlers.ManageAdminUsers())
		manageAdmin.GET("/domains", handlers.ManageAdminDomains())

		manageAdmin.POST("/users", handlers.PostUser())

		manageAdmin.GET("/partials/users_list", handlers.AdminPartialUsersList())
	}

	return r
}