From 0b85a41b69cffc07f0388ec3d3255187dcae47e8 Mon Sep 17 00:00:00 2001 From: E99p1ant Date: Sun, 11 Feb 2024 21:58:51 +0800 Subject: [PATCH] pixel: init --- internal/conf/conf.go | 4 +++ internal/conf/static.go | 4 +++ internal/context/context.go | 5 ++- internal/route/route.go | 4 +++ route/pixel/pixel.go | 62 +++++++++++++++++++++++++++++++++++++ templates/base/footer.html | 3 +- templates/base/header.html | 4 +++ templates/embed.go | 2 +- templates/pixel.html | 8 +++++ 9 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 route/pixel/pixel.go create mode 100644 templates/pixel.html diff --git a/internal/conf/conf.go b/internal/conf/conf.go index 8a54bf3..61e6fe5 100644 --- a/internal/conf/conf.go +++ b/internal/conf/conf.go @@ -58,6 +58,10 @@ func Init() error { return errors.Wrap(err, "map 'recaptcha'") } + if err := File.Section("pixel").MapTo(&Pixel); err != nil { + return errors.Wrap(err, "map 'pixel'") + } + if err := File.Section("upload").MapTo(&Upload); err != nil { return errors.Wrap(err, "map 'upload'") } diff --git a/internal/conf/static.go b/internal/conf/static.go index 5a97fa4..d6a170e 100644 --- a/internal/conf/static.go +++ b/internal/conf/static.go @@ -55,6 +55,10 @@ var ( TurnstileStyle bool `ini:"turnstile_style"` } + Pixel struct { + Host string `ini:"host"` + } + Upload struct { DefaultAvatarURL string `ini:"default_avatar"` DefaultBackground string `ini:"default_background"` diff --git a/internal/context/context.go b/internal/context/context.go index cfa9020..61c5023 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -9,6 +9,7 @@ import ( "fmt" "net/http" "reflect" + "strings" "github.com/flamego/csrf" "github.com/flamego/flamego" @@ -158,7 +159,7 @@ func Contexter() flamego.Handler { Template: t, } - if ctx.Request().Method == http.MethodPost { + if ctx.Request().Method == http.MethodPost && !strings.HasPrefix(ctx.Request().URL.Path, "/api/v1/pixel/") { x.Validate(ctx) } @@ -179,6 +180,8 @@ func Contexter() flamego.Handler { c.Data["LoggedUserName"] = "" } + c.Data["IsPixel"] = ctx.Request().URL.Path == "/pixel" + span := trace.SpanFromContext(ctx.Request().Context()) if span.IsRecording() { span.SetAttributes( diff --git a/internal/route/route.go b/internal/route/route.go index 4435915..1999541 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -27,6 +27,7 @@ import ( templatepkg "github.com/NekoWheel/NekoBox/internal/template" "github.com/NekoWheel/NekoBox/route" "github.com/NekoWheel/NekoBox/route/auth" + "github.com/NekoWheel/NekoBox/route/pixel" "github.com/NekoWheel/NekoBox/route/question" "github.com/NekoWheel/NekoBox/route/user" "github.com/NekoWheel/NekoBox/static" @@ -83,6 +84,7 @@ func New() *flamego.Flame { f.Group("", func() { f.Get("/", route.Home) + f.Get("/pixel", reqUserSignIn, pixel.Index) f.Get("/sponsor", route.Sponsor) f.Get("/change-logs", route.ChangeLogs) f.Get("/robots.txt", func(c context.Context) { @@ -137,6 +139,8 @@ func New() *flamego.Flame { }) }) }) + + f.Any("/pixel/{**}", reqUserSignIn, pixel.Proxy) }, context.APIEndpoint) }, cache.Cacher(cache.Options{ diff --git a/route/pixel/pixel.go b/route/pixel/pixel.go new file mode 100644 index 0000000..b452b54 --- /dev/null +++ b/route/pixel/pixel.go @@ -0,0 +1,62 @@ +// Copyright 2024 E99p1ant. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package pixel + +import ( + "io" + "net/http" + "path" + "strconv" + + "github.com/sirupsen/logrus" + + "github.com/NekoWheel/NekoBox/internal/conf" + "github.com/NekoWheel/NekoBox/internal/context" +) + +func Index(ctx context.Context) { + ctx.Success("pixel") +} + +func Proxy(ctx context.Context) error { + uri := ctx.Param("**") + method := ctx.Request().Method + userID := strconv.Itoa(int(ctx.User.ID)) + + var body io.Reader + if method == http.MethodPost || method == http.MethodPut { + body = ctx.Request().Request.Body + } + + req, err := http.NewRequest(method, "http://pixel/", body) + if err != nil { + logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to create request") + return ctx.ServerError() + } + req.URL.Host = conf.Pixel.Host + req.URL.Path = path.Join("/api/", uri) + req.Header.Set("neko-user-id", userID) + + client := http.Client{} + resp, err := client.Do(req) + if err != nil { + logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to send request") + return ctx.ServerError() + } + defer func() { _ = resp.Body.Close() }() + + for k, v := range resp.Header { + ctx.ResponseWriter().Header()[k] = v + } + ctx.ResponseWriter().WriteHeader(resp.StatusCode) + + _, err = io.Copy(ctx.ResponseWriter(), resp.Body) + if err != nil { + logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to copy response") + return ctx.ServerError() + } + + return nil +} diff --git a/templates/base/footer.html b/templates/base/footer.html index a866968..40e0503 100644 --- a/templates/base/footer.html +++ b/templates/base/footer.html @@ -1,6 +1,7 @@ -

+

Made with ❤️ by E99p1ant. {{ ICP }}
+ 画板 | GitHub | {{ CommitSHAShort }} | 吐槽反馈 diff --git a/templates/base/header.html b/templates/base/header.html index 8019f3b..84f30eb 100644 --- a/templates/base/header.html +++ b/templates/base/header.html @@ -88,4 +88,8 @@ +{{ if .IsPixel }} +

+{{ else }}
+{{ end }} diff --git a/templates/embed.go b/templates/embed.go index 1d8b0c7..695a7a1 100644 --- a/templates/embed.go +++ b/templates/embed.go @@ -8,5 +8,5 @@ import ( "embed" ) -//go:embed auth base mail question user home.html sponsor.html change-logs.html +//go:embed auth base mail question user home.html sponsor.html change-logs.html pixel.html var FS embed.FS diff --git a/templates/pixel.html b/templates/pixel.html new file mode 100644 index 0000000..20e0bd0 --- /dev/null +++ b/templates/pixel.html @@ -0,0 +1,8 @@ +{{template "base/header" .}} + +
+ + +{{template "base/footer" .}}