Transformers

This commit is contained in:
2023-11-18 00:23:40 +08:00
parent 2fc1ef89db
commit ff1f1dbc9d
13 changed files with 257 additions and 98 deletions

View File

@ -0,0 +1,10 @@
package configurator
import "encoding/json"
func DeserializeOptions[T any](data any) T {
var out T
raw, _ := json.Marshal(data)
_ = json.Unmarshal(raw, &out)
return out
}

View File

@ -0,0 +1,41 @@
package configurator
import (
"math/rand"
)
type AppConfig struct {
Sites []SiteConfig `json:"sites"`
}
func (v *AppConfig) LoadBalance(site SiteConfig) *UpstreamConfig {
idx := rand.Intn(len(site.Upstreams))
switch site.Upstreams[idx].GetType() {
case UpstreamTypeHypertext:
return &site.Upstreams[idx]
case UpstreamTypeFile:
// TODO Make this into hypertext configuration
return &site.Upstreams[idx]
default:
// Give him the null value when this configuration is invalid.
// Then we can print a log in the console to warm him.
return nil
}
}
type SiteConfig struct {
ID string `json:"id"`
Name string `json:"name"`
Rules []RouterRuleConfig `json:"rules"`
Transformers []RequestTransformerConfig `json:"transformers"`
Upstreams []UpstreamConfig `json:"upstreams"`
}
type RouterRuleConfig struct {
Host []string `json:"host"`
Path []string `json:"path"`
Queries map[string]string `json:"query"`
Headers map[string][]string `json:"headers"`
}

View File

@ -1,46 +0,0 @@
package configurator
import "strings"
type AppConfig struct {
Sites []SiteConfig `json:"sites"`
}
type SiteConfig struct {
ID string `json:"id"`
Name string `json:"name"`
Rules []RouterRuleConfig `json:"rules"`
Upstreams []UpstreamConfig `json:"upstreams"`
}
type RouterRuleConfig struct {
Host []string `json:"host"`
Path []string `json:"path"`
Queries map[string]string `json:"query"`
Headers map[string][]string `json:"headers"`
}
const (
UpstreamTypeFile = "file"
UpstreamTypeHypertext = "hypertext"
UpstreamTypeUnknown = "unknown"
)
type UpstreamConfig struct {
Name string `json:"name"`
URI string `json:"uri"`
}
func (v *UpstreamConfig) GetType() string {
protocol := strings.SplitN(v.URI, "://", 2)[0]
switch protocol {
case "file":
return UpstreamTypeFile
case "http":
case "https":
return UpstreamTypeHypertext
}
return UpstreamTypeUnknown
}

View File

@ -0,0 +1,58 @@
package configurator
import (
"github.com/gofiber/fiber/v2"
"regexp"
"strings"
)
type RequestTransformer struct {
ModifyRequest func(options any, ctx *fiber.Ctx)
ModifyResponse func(options any, ctx *fiber.Ctx)
}
type RequestTransformerConfig struct {
Type string `json:"type"`
Options any `json:"options"`
}
func (v *RequestTransformerConfig) TransformRequest(ctx *fiber.Ctx) {
for k, f := range Transformers {
if k == v.Type {
if f.ModifyRequest != nil {
f.ModifyRequest(v.Options, ctx)
}
break
}
}
}
func (v *RequestTransformerConfig) TransformResponse(ctx *fiber.Ctx) {
for k, f := range Transformers {
if k == v.Type {
if f.ModifyResponse != nil {
f.ModifyResponse(v.Options, ctx)
}
break
}
}
}
var Transformers = map[string]RequestTransformer{
"replacePath": {
ModifyRequest: func(options any, ctx *fiber.Ctx) {
opts := DeserializeOptions[struct {
Pattern string `json:"pattern"`
Value string `json:"value"`
Repl string `json:"repl"` // Use when complex mode(regexp) enabled
Complex bool `json:"complex"`
}](options)
path := string(ctx.Request().URI().Path())
if !opts.Complex {
ctx.Path(strings.ReplaceAll(path, opts.Pattern, opts.Value))
} else if ex := regexp.MustCompile(opts.Pattern); ex != nil {
ctx.Path(ex.ReplaceAllString(path, opts.Repl))
}
},
},
}

View File

@ -0,0 +1,46 @@
package configurator
import (
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/samber/lo"
"strings"
)
const (
UpstreamTypeFile = "file"
UpstreamTypeHypertext = "hypertext"
UpstreamTypeUnknown = "unknown"
)
type UpstreamConfig struct {
Name string `json:"name"`
URI string `json:"uri"`
}
func (v *UpstreamConfig) GetType() string {
protocol := strings.SplitN(v.URI, "://", 2)[0]
switch protocol {
case "file":
return UpstreamTypeFile
case "http":
case "https":
return UpstreamTypeHypertext
}
return UpstreamTypeUnknown
}
func (v *UpstreamConfig) MakeURI(ctx *fiber.Ctx) string {
var queries []string
for k, v := range ctx.Queries() {
queries = append(queries, fmt.Sprintf("%s=%s", k, v))
}
path := string(ctx.Request().URI().Path())
hash := string(ctx.Request().URI().Hash())
return v.URI + path +
lo.Ternary(len(queries) > 0, "?"+strings.Join(queries, "&"), "") +
lo.Ternary(len(hash) > 0, "#"+hash, "")
}