From 5ae31d8a07cf82bb14312fb2b3f5e477cb5e6c81 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 18 Nov 2023 14:30:35 +0800 Subject: [PATCH] :sparkles: Publish --- README.md | 2 +- config/example.json | 1 + pkg/administration/init.go | 6 +++ pkg/administration/publish.go | 63 ++++++++++++++++++++++++++++++ pkg/cmd/main.go | 2 +- pkg/fs/zip.go | 72 +++++++++++++++++++++++++++++++++++ pkg/hypertext/init.go | 1 - pkg/hypertext/proxies.go | 4 +- pkg/sign/configurator.go | 4 +- pkg/sign/upstream.go | 2 + 10 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 pkg/administration/publish.go create mode 100644 pkg/fs/zip.go diff --git a/README.md b/README.md index 1f0bfc7..0a94624 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A blazing fast reverse proxy with a lot of shining features. 2. Static file hosting 3. ~~Analytics and Metrics~~ 4. Integrate with CI/CD -5. ~~Webhook integration~~ +5. Webhook integration 6. ~~Web management panel~~ 7. **Blazing fast ⚡** diff --git a/config/example.json b/config/example.json index fc43bf0..8adea5b 100644 --- a/config/example.json +++ b/config/example.json @@ -12,6 +12,7 @@ ], "upstreams": [ { + "id": "example", "name": "Example Upstream", "uri": "file://C:\\site" } diff --git a/pkg/administration/init.go b/pkg/administration/init.go index ed527ff..ac6a5d2 100644 --- a/pkg/administration/init.go +++ b/pkg/administration/init.go @@ -13,8 +13,14 @@ func InitAdministration() *fiber.App { ServerHeader: fmt.Sprintf("RoadSign Administration v%s", roadsign.AppVersion), DisableStartupMessage: true, EnableIPValidation: true, + EnablePrintRoutes: viper.GetBool("debug.print_routes"), TrustedProxies: viper.GetStringSlice("security.administration_trusted_proxies"), }) + webhooks := app.Group("/webhooks").Name("WebHooks") + { + webhooks.Put("/publish/:site/:upstream", doPublish) + } + return app } diff --git a/pkg/administration/publish.go b/pkg/administration/publish.go new file mode 100644 index 0000000..dcb6d9b --- /dev/null +++ b/pkg/administration/publish.go @@ -0,0 +1,63 @@ +package administration + +import ( + "code.smartsheep.studio/goatworks/roadsign/pkg/fs" + "code.smartsheep.studio/goatworks/roadsign/pkg/sign" + "github.com/gofiber/fiber/v2" + "github.com/google/uuid" + "os" + "path/filepath" +) + +func doPublish(ctx *fiber.Ctx) error { + var upstream *sign.UpstreamConfig + for _, item := range sign.App.Sites { + if item.ID == ctx.Params("site") { + for _, stream := range item.Upstreams { + if stream.ID == ctx.Params("upstream") { + upstream = &stream + break + } + } + break + } + } + + if upstream == nil { + return fiber.ErrNotFound + } else if upstream.GetType() != sign.UpstreamTypeFile { + return fiber.ErrUnprocessableEntity + } + + workdir, _ := upstream.GetRawURI() + + if ctx.Query("overwrite", "yes") == "yes" { + files, _ := filepath.Glob(filepath.Join(workdir, "*")) + for _, file := range files { + _ = os.Remove(file) + } + } + + if form, err := ctx.MultipartForm(); err == nil { + files := form.File["attachments"] + for _, file := range files { + mimetype := file.Header["Content-Type"][0] + switch mimetype { + case "application/zip": + dst := filepath.Join(os.TempDir(), uuid.NewString()+".zip") + if err := ctx.SaveFile(file, dst); err != nil { + return err + } else { + _ = fs.Unzip(dst, workdir) + } + default: + dst := filepath.Join(workdir, file.Filename) + if err := ctx.SaveFile(file, dst); err != nil { + return err + } + } + } + } + + return ctx.SendStatus(fiber.StatusOK) +} diff --git a/pkg/cmd/main.go b/pkg/cmd/main.go index 1b7d43e..a29011a 100644 --- a/pkg/cmd/main.go +++ b/pkg/cmd/main.go @@ -34,7 +34,7 @@ func main() { if err := sign.ReadInConfig(viper.GetString("paths.configs")); err != nil { log.Panic().Err(err).Msg("An error occurred when loading configurations.") } else { - log.Debug().Any("sites", sign.C).Msg("All configuration has been loaded.") + log.Debug().Any("sites", sign.App).Msg("All configuration has been loaded.") } // Init hypertext server diff --git a/pkg/fs/zip.go b/pkg/fs/zip.go new file mode 100644 index 0000000..4a33e0c --- /dev/null +++ b/pkg/fs/zip.go @@ -0,0 +1,72 @@ +package fs + +import ( + "archive/zip" + "fmt" + "io" + "os" + "path/filepath" + "strings" +) + +func Unzip(src, dest string) error { + r, err := zip.OpenReader(src) + if err != nil { + return err + } + defer func() { + if err := r.Close(); err != nil { + panic(err) + } + }() + + _ = os.MkdirAll(dest, 0755) + + extract := func(f *zip.File) error { + rc, err := f.Open() + if err != nil { + return err + } + defer func() { + if err := rc.Close(); err != nil { + panic(err) + } + }() + + path := filepath.Join(dest, f.Name) + + if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) { + return fmt.Errorf("illegal file path: %s", path) + } + + if f.FileInfo().IsDir() { + _ = os.MkdirAll(path, f.Mode()) + } else { + _ = os.MkdirAll(filepath.Dir(path), f.Mode()) + f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return err + } + defer func() { + if err := f.Close(); err != nil { + panic(err) + } + }() + + _, err = io.Copy(f, rc) + if err != nil { + return err + } + } + return nil + } + + for _, f := range r.File { + err := extract(f) + if err != nil { + return err + } + } + + return nil +} diff --git a/pkg/hypertext/init.go b/pkg/hypertext/init.go index 517ed51..60cd365 100644 --- a/pkg/hypertext/init.go +++ b/pkg/hypertext/init.go @@ -16,7 +16,6 @@ func InitServer() *fiber.App { ServerHeader: fmt.Sprintf("RoadSign v%s", roadsign.AppVersion), DisableStartupMessage: true, EnableIPValidation: true, - EnablePrintRoutes: viper.GetBool("debug.print_routes"), Prefork: viper.GetBool("performance.prefork"), BodyLimit: viper.GetInt("hypertext.limitation.max_body_size"), }) diff --git a/pkg/hypertext/proxies.go b/pkg/hypertext/proxies.go index 2cb1141..db3112a 100644 --- a/pkg/hypertext/proxies.go +++ b/pkg/hypertext/proxies.go @@ -15,7 +15,7 @@ func UseProxies(app *fiber.App) { headers := ctx.GetReqHeaders() // Filtering sites - for _, site := range sign.C.Sites { + for _, site := range sign.App.Sites { // Matching rules for _, rule := range site.Rules { if !lo.Contains(rule.Host, host) { @@ -95,7 +95,7 @@ func makeResponse(ctx *fiber.Ctx, site sign.SiteConfig) error { } // Forward - err := sign.C.Forward(ctx, site) + err := sign.App.Forward(ctx, site) // Modify response for _, transformer := range site.Transformers { diff --git a/pkg/sign/configurator.go b/pkg/sign/configurator.go index 36ef9ef..3f8ff71 100644 --- a/pkg/sign/configurator.go +++ b/pkg/sign/configurator.go @@ -8,7 +8,7 @@ import ( "strings" ) -var C *AppConfig +var App *AppConfig func ReadInConfig(root string) error { cfg := &AppConfig{ @@ -37,7 +37,7 @@ func ReadInConfig(root string) error { return err } - C = cfg + App = cfg return nil } diff --git a/pkg/sign/upstream.go b/pkg/sign/upstream.go index 2abf968..f2eb692 100644 --- a/pkg/sign/upstream.go +++ b/pkg/sign/upstream.go @@ -15,6 +15,8 @@ const ( ) type UpstreamConfig struct { + ID string `json:"id"` + Name string `json:"name"` URI string `json:"uri"` }