Status pages
All checks were successful
release-nightly / build-docker (push) Successful in 1m53s

This commit is contained in:
LittleSheep 2024-01-31 15:13:57 +08:00
parent d2710d1718
commit 6607e1dc5e
16 changed files with 291 additions and 73 deletions

View File

@ -11,5 +11,6 @@
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Python 3.9 interpreter library" level="application" /> <orderEntry type="library" name="Python 3.9 interpreter library" level="application" />
<orderEntry type="library" name="daisyui" level="application" />
</component> </component>
</module> </module>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="PROJECT" libraries="{daisyui}" />
</component>
</project>

3
go.mod
View File

@ -17,6 +17,9 @@ require (
require ( require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/gofiber/template v1.8.2 // indirect
github.com/gofiber/template/html/v2 v2.1.0 // indirect
github.com/gofiber/utils v1.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect

6
go.sum
View File

@ -16,6 +16,12 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofiber/fiber/v2 v2.52.0 h1:S+qXi7y+/Pgvqq4DrSmREGiFwtB7Bu6+QFLuIHYw/UE= github.com/gofiber/fiber/v2 v2.52.0 h1:S+qXi7y+/Pgvqq4DrSmREGiFwtB7Bu6+QFLuIHYw/UE=
github.com/gofiber/fiber/v2 v2.52.0/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/gofiber/fiber/v2 v2.52.0/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
github.com/gofiber/template v1.8.2 h1:PIv9s/7Uq6m+Fm2MDNd20pAFFKt5wWs7ZBd8iV9pWwk=
github.com/gofiber/template v1.8.2/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8=
github.com/gofiber/template/html/v2 v2.1.0 h1:FjwzqhhdJpnhyCvav60Z1ytnBqOUr5sGO/aTeob9/ng=
github.com/gofiber/template/html/v2 v2.1.0/go.mod h1:txXsRQN/G7Fr2cqGfr6zhVHgreCfpsBS+9+DJyrddJc=
github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM=
github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=

View File

@ -10,8 +10,7 @@ import (
"github.com/samber/lo" "github.com/samber/lo"
) )
func UseProxies(app *fiber.App) { func ProxiesHandler(ctx *fiber.Ctx) error {
app.All("/*", func(ctx *fiber.Ctx) error {
host := ctx.Hostname() host := ctx.Hostname()
path := ctx.Path() path := ctx.Path()
queries := ctx.Queries() queries := ctx.Queries()
@ -91,7 +90,6 @@ func UseProxies(app *fiber.App) {
// Just ignore it and give our client a not found status. // Just ignore it and give our client a not found status.
// Do not care about the user experience, we can do it in custom error handler. // Do not care about the user experience, we can do it in custom error handler.
return fiber.ErrNotFound return fiber.ErrNotFound
})
} }
func makeResponse(c *fiber.Ctx, region *navi.Region, location *navi.Location, dest *navi.Destination) error { func makeResponse(c *fiber.Ctx, region *navi.Region, location *navi.Location, dest *navi.Destination) error {

View File

@ -1,25 +1,32 @@
package hypertext package hypertext
import ( import (
"code.smartsheep.studio/goatworks/roadsign/pkg/hypertext/status"
"crypto/tls" "crypto/tls"
jsoniter "github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
"net" "net"
"net/http"
"strings" "strings"
"time" "time"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/limiter" "github.com/gofiber/fiber/v2/middleware/limiter"
"github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/template/html/v2"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
func InitServer() *fiber.App { func InitServer() *fiber.App {
views := html.NewFileSystem(http.FS(status.FS), ".gohtml")
app := fiber.New(fiber.Config{ app := fiber.New(fiber.Config{
ViewsLayout: "views/index",
AppName: "RoadSign", AppName: "RoadSign",
ServerHeader: "RoadSign", ServerHeader: "RoadSign",
DisableStartupMessage: true, DisableStartupMessage: true,
EnableIPValidation: true, EnableIPValidation: true,
Views: views,
ErrorHandler: status.StatusPageHandler,
JSONDecoder: jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal, JSONDecoder: jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal,
JSONEncoder: jsoniter.ConfigCompatibleWithStandardLibrary.Marshal, JSONEncoder: jsoniter.ConfigCompatibleWithStandardLibrary.Marshal,
Prefork: viper.GetBool("performance.prefork"), Prefork: viper.GetBool("performance.prefork"),
@ -50,10 +57,13 @@ func InitServer() *fiber.App {
app.Use(limiter.New(limiter.Config{ app.Use(limiter.New(limiter.Config{
Max: viper.GetInt("hypertext.limitation.max_qps"), Max: viper.GetInt("hypertext.limitation.max_qps"),
Expiration: 1 * time.Second, Expiration: 1 * time.Second,
LimitReached: func(c *fiber.Ctx) error {
return fiber.ErrTooManyRequests
},
})) }))
} }
UseProxies(app) app.All("/*", ProxiesHandler)
return app return app
} }

View File

@ -0,0 +1,6 @@
package status
import "embed"
//go:embed all:views
var FS embed.FS

View File

@ -0,0 +1,56 @@
package status
import (
roadsign "code.smartsheep.studio/goatworks/roadsign/pkg"
"errors"
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/spf13/viper"
)
type ErrorPayload struct {
Title string `json:"title"`
Message string `json:"message"`
Version string `json:"version"`
}
func StatusPageHandler(c *fiber.Ctx, err error) error {
var reqErr *fiber.Error
var status = fiber.StatusInternalServerError
if errors.As(err, &reqErr) {
status = reqErr.Code
}
c.Status(status)
payload := ErrorPayload{
Version: roadsign.AppVersion,
}
switch status {
case fiber.StatusNotFound:
payload.Title = "Not Found"
payload.Message = fmt.Sprintf("no resource for \"%s\"", c.OriginalURL())
return c.Render("views/not-found", payload)
case fiber.StatusTooManyRequests:
payload.Title = "Request Too Fast"
payload.Message = fmt.Sprintf("you have sent over %d request(s) in a second", viper.GetInt("hypertext.limitation.max_qps"))
return c.Render("views/too-many-requests", payload)
case fiber.StatusRequestEntityTooLarge:
payload.Title = "Request Too Large"
payload.Message = fmt.Sprintf("you have sent a request over %d bytes", viper.GetInt("hypertext.limitation.max_body_size"))
return c.Render("views/request-too-large", payload)
case fiber.StatusBadGateway:
payload.Title = "Backend Down"
payload.Message = fmt.Sprintf("all destnations configured to handle your request are down: %s", err.Error())
return c.Render("views/bad-gateway", payload)
case fiber.StatusGatewayTimeout:
payload.Title = "Backend Took Too Long To Response"
payload.Message = fmt.Sprintf("the destnation took too long to response your request: %s", err.Error())
return c.Render("views/gateway-timeout", payload)
default:
payload.Title = "Oops"
payload.Message = err.Error()
return c.Render("views/fallback", payload)
}
}

View File

@ -0,0 +1,6 @@
<h1 class="text-2xl font-bold">502</h1>
<h2 class="text-lg">No one is standing...</h2>
<div class="mt-3 mx-auto p-5 w-[360px] max-w-screen bg-neutral text-neutral-content rounded">
<code class="capitalize">{{ .Message }}</code>
</div>

View File

@ -0,0 +1,6 @@
<h1 class="text-2xl font-bold">Oops</h1>
<h2 class="text-lg">Something went wrong...</h2>
<div class="mt-3 mx-auto p-5 w-[360px] max-w-screen bg-neutral text-neutral-content rounded">
<code class="capitalize">{{ .Message }}</code>
</div>

View File

@ -0,0 +1,6 @@
<h1 class="text-2xl font-bold">504</h1>
<h2 class="text-lg">Looks like the server in the back fell asleep</h2>
<div class="mt-3 mx-auto p-5 w-[360px] max-w-screen bg-neutral text-neutral-content rounded">
<code class="capitalize">{{ .Message }}</code>
</div>

View File

@ -0,0 +1,83 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/daisyui@4.6.1/dist/full.min.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
daisyui: {
themes: [
{
light: {
primary: "#4750a3",
secondary: "#93c5fd",
accent: "#0f766e",
info: "#67e8f9",
success: "#15803d",
warning: "#f97316",
error: "#dc2626",
neutral: "#2B3440",
"secondary-content": "oklch(98.71% 0.0106 342.55)",
"neutral-content": "#D7DDE4",
"base-100": "oklch(100% 0 0)",
"base-200": "#F2F2F2",
"base-300": "#E5E6E6",
"base-content": "#1f2937",
"color-scheme": "light",
"--rounded-box": "0",
"--rounded-btn": "0",
"--rounded-badge": "0",
"--tab-radius": "0"
}
},
{
dark: {
primary: "#4750a3",
secondary: "#93c5fd",
accent: "#0f766e",
info: "#67e8f9",
success: "#15803d",
warning: "#f97316",
error: "#dc2626",
neutral: "#2a323c",
"neutral-content": "#A6ADBB",
"base-100": "#1d232a",
"base-200": "#191e24",
"base-300": "#15191e",
"base-content": "#A6ADBB",
"color-scheme": "dark",
"--rounded-box": "0",
"--rounded-btn": "0",
"--rounded-badge": "0",
"--tab-radius": "0"
}
}
]
}
}
</script>
<title>{{ .Title }} | RoadSign</title>
</head>
<body>
<main class="w-full h-screen flex justify-center items-center">
<div class="text-center">
{{embed}}
<footer class="mt-3 text-sm text-neutral">
<p>
Powered by
<a href="https://wiki.smartsheep.studio/roadsign/index.html" target="_blank" class="link link-primary">
RoadSign
</a>
</p>
<p class="text-xs">v{{ .Version }}</p>
</footer>
</div>
</main>
</body>
</html>

View File

@ -0,0 +1,6 @@
<h1 class="text-2xl font-bold">404</h1>
<h2 class="text-lg">Not Found</h2>
<div class="mt-3 mx-auto p-5 w-[360px] max-w-screen bg-neutral text-neutral-content rounded">
<code class="capitalize">{{ .Message }}</code>
</div>

View File

@ -0,0 +1,6 @@
<h1 class="text-2xl font-bold">413</h1>
<h2 class="text-lg">Auh, you are too big.</h2>
<div class="mt-3 mx-auto p-5 w-[360px] max-w-screen bg-neutral text-neutral-content rounded">
<code class="capitalize">{{ .Message }}</code>
</div>

View File

@ -0,0 +1,6 @@
<h1 class="text-2xl font-bold">429</h1>
<h2 class="text-lg">Stop it, you just to fast!</h2>
<div class="mt-3 mx-auto p-5 w-[360px] max-w-screen bg-neutral text-neutral-content rounded">
<code class="capitalize">{{ .Message }}</code>
</div>

View File

@ -1,14 +1,13 @@
/** @type {import('tailwindcss').Config} */ /** @type {import("tailwindcss").Config} */
export default { export default {
content: ["./src/**/*.{js,jsx,ts,tsx}"], content: ["./src/**/*.{js,jsx,ts,tsx}"],
theme: { theme: {
extend: {}, extend: {}
}, },
daisyui: { daisyui: {
themes: [ themes: [
{ {
light: { light: {
...require("daisyui/src/theming/themes")["light"],
primary: "#4750a3", primary: "#4750a3",
secondary: "#93c5fd", secondary: "#93c5fd",
accent: "#0f766e", accent: "#0f766e",
@ -16,15 +15,22 @@ export default {
success: "#15803d", success: "#15803d",
warning: "#f97316", warning: "#f97316",
error: "#dc2626", error: "#dc2626",
neutral: "#2B3440",
"secondary-content": "oklch(98.71% 0.0106 342.55)",
"neutral-content": "#D7DDE4",
"base-100": "oklch(100% 0 0)",
"base-200": "#F2F2F2",
"base-300": "#E5E6E6",
"base-content": "#1f2937",
"color-scheme": "light",
"--rounded-box": "0", "--rounded-box": "0",
"--rounded-btn": "0", "--rounded-btn": "0",
"--rounded-badge": "0", "--rounded-badge": "0",
"--tab-radius": "0", "--tab-radius": "0"
}, }
}, },
{ {
dark: { dark: {
...require("daisyui/src/theming/themes")["dark"],
primary: "#4750a3", primary: "#4750a3",
secondary: "#93c5fd", secondary: "#93c5fd",
accent: "#0f766e", accent: "#0f766e",
@ -32,13 +38,20 @@ export default {
success: "#15803d", success: "#15803d",
warning: "#f97316", warning: "#f97316",
error: "#dc2626", error: "#dc2626",
neutral: "#2a323c",
"neutral-content": "#A6ADBB",
"base-100": "#1d232a",
"base-200": "#191e24",
"base-300": "#15191e",
"base-content": "#A6ADBB",
"color-scheme": "dark",
"--rounded-box": "0", "--rounded-box": "0",
"--rounded-btn": "0", "--rounded-btn": "0",
"--rounded-badge": "0", "--rounded-badge": "0",
"--tab-radius": "0", "--tab-radius": "0"
}
}
]
}, },
}, plugins: [require("daisyui")]
], }
},
plugins: [require("daisyui")],
};