✨ Publish
This commit is contained in:
parent
61ab586f4f
commit
5ae31d8a07
@ -8,7 +8,7 @@ A blazing fast reverse proxy with a lot of shining features.
|
|||||||
2. Static file hosting
|
2. Static file hosting
|
||||||
3. ~~Analytics and Metrics~~
|
3. ~~Analytics and Metrics~~
|
||||||
4. Integrate with CI/CD
|
4. Integrate with CI/CD
|
||||||
5. ~~Webhook integration~~
|
5. Webhook integration
|
||||||
6. ~~Web management panel~~
|
6. ~~Web management panel~~
|
||||||
7. **Blazing fast ⚡**
|
7. **Blazing fast ⚡**
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
],
|
],
|
||||||
"upstreams": [
|
"upstreams": [
|
||||||
{
|
{
|
||||||
|
"id": "example",
|
||||||
"name": "Example Upstream",
|
"name": "Example Upstream",
|
||||||
"uri": "file://C:\\site"
|
"uri": "file://C:\\site"
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,14 @@ func InitAdministration() *fiber.App {
|
|||||||
ServerHeader: fmt.Sprintf("RoadSign Administration v%s", roadsign.AppVersion),
|
ServerHeader: fmt.Sprintf("RoadSign Administration v%s", roadsign.AppVersion),
|
||||||
DisableStartupMessage: true,
|
DisableStartupMessage: true,
|
||||||
EnableIPValidation: true,
|
EnableIPValidation: true,
|
||||||
|
EnablePrintRoutes: viper.GetBool("debug.print_routes"),
|
||||||
TrustedProxies: viper.GetStringSlice("security.administration_trusted_proxies"),
|
TrustedProxies: viper.GetStringSlice("security.administration_trusted_proxies"),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
webhooks := app.Group("/webhooks").Name("WebHooks")
|
||||||
|
{
|
||||||
|
webhooks.Put("/publish/:site/:upstream", doPublish)
|
||||||
|
}
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
63
pkg/administration/publish.go
Normal file
63
pkg/administration/publish.go
Normal file
@ -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)
|
||||||
|
}
|
@ -34,7 +34,7 @@ func main() {
|
|||||||
if err := sign.ReadInConfig(viper.GetString("paths.configs")); err != nil {
|
if err := sign.ReadInConfig(viper.GetString("paths.configs")); err != nil {
|
||||||
log.Panic().Err(err).Msg("An error occurred when loading configurations.")
|
log.Panic().Err(err).Msg("An error occurred when loading configurations.")
|
||||||
} else {
|
} 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
|
// Init hypertext server
|
||||||
|
72
pkg/fs/zip.go
Normal file
72
pkg/fs/zip.go
Normal file
@ -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
|
||||||
|
}
|
@ -16,7 +16,6 @@ func InitServer() *fiber.App {
|
|||||||
ServerHeader: fmt.Sprintf("RoadSign v%s", roadsign.AppVersion),
|
ServerHeader: fmt.Sprintf("RoadSign v%s", roadsign.AppVersion),
|
||||||
DisableStartupMessage: true,
|
DisableStartupMessage: true,
|
||||||
EnableIPValidation: true,
|
EnableIPValidation: true,
|
||||||
EnablePrintRoutes: viper.GetBool("debug.print_routes"),
|
|
||||||
Prefork: viper.GetBool("performance.prefork"),
|
Prefork: viper.GetBool("performance.prefork"),
|
||||||
BodyLimit: viper.GetInt("hypertext.limitation.max_body_size"),
|
BodyLimit: viper.GetInt("hypertext.limitation.max_body_size"),
|
||||||
})
|
})
|
||||||
|
@ -15,7 +15,7 @@ func UseProxies(app *fiber.App) {
|
|||||||
headers := ctx.GetReqHeaders()
|
headers := ctx.GetReqHeaders()
|
||||||
|
|
||||||
// Filtering sites
|
// Filtering sites
|
||||||
for _, site := range sign.C.Sites {
|
for _, site := range sign.App.Sites {
|
||||||
// Matching rules
|
// Matching rules
|
||||||
for _, rule := range site.Rules {
|
for _, rule := range site.Rules {
|
||||||
if !lo.Contains(rule.Host, host) {
|
if !lo.Contains(rule.Host, host) {
|
||||||
@ -95,7 +95,7 @@ func makeResponse(ctx *fiber.Ctx, site sign.SiteConfig) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Forward
|
// Forward
|
||||||
err := sign.C.Forward(ctx, site)
|
err := sign.App.Forward(ctx, site)
|
||||||
|
|
||||||
// Modify response
|
// Modify response
|
||||||
for _, transformer := range site.Transformers {
|
for _, transformer := range site.Transformers {
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var C *AppConfig
|
var App *AppConfig
|
||||||
|
|
||||||
func ReadInConfig(root string) error {
|
func ReadInConfig(root string) error {
|
||||||
cfg := &AppConfig{
|
cfg := &AppConfig{
|
||||||
@ -37,7 +37,7 @@ func ReadInConfig(root string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
C = cfg
|
App = cfg
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type UpstreamConfig struct {
|
type UpstreamConfig struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
URI string `json:"uri"`
|
URI string `json:"uri"`
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user