新增格式转换插件,新增http日志变量,调整json输出请求日志格式

This commit is contained in:
Liujian
2023-08-24 15:44:00 +08:00
parent 9a7136c677
commit 62618fde7c
39 changed files with 599 additions and 361 deletions

View File

@@ -3,6 +3,7 @@ package main
import ( import (
"github.com/eolinker/apinto/drivers/plugins/app" "github.com/eolinker/apinto/drivers/plugins/app"
"github.com/eolinker/apinto/drivers/plugins/cors" "github.com/eolinker/apinto/drivers/plugins/cors"
data_transform "github.com/eolinker/apinto/drivers/plugins/data-transform"
dubbo2_proxy_rewrite "github.com/eolinker/apinto/drivers/plugins/dubbo2-proxy-rewrite" dubbo2_proxy_rewrite "github.com/eolinker/apinto/drivers/plugins/dubbo2-proxy-rewrite"
extra_params "github.com/eolinker/apinto/drivers/plugins/extra-params" extra_params "github.com/eolinker/apinto/drivers/plugins/extra-params"
grpc_proxy_rewrite "github.com/eolinker/apinto/drivers/plugins/grpc-proxy-rewrite" grpc_proxy_rewrite "github.com/eolinker/apinto/drivers/plugins/grpc-proxy-rewrite"
@@ -66,6 +67,7 @@ func pluginRegister(extenderRegister eosc.IExtenderDriverRegister) {
proxy_rewrite_v2.Register(extenderRegister) proxy_rewrite_v2.Register(extenderRegister)
http_mocking.Register(extenderRegister) http_mocking.Register(extenderRegister)
params_check.Register(extenderRegister) params_check.Register(extenderRegister)
data_transform.Register(extenderRegister)
// 响应处理插件 // 响应处理插件
response_rewrite.Register(extenderRegister) response_rewrite.Register(extenderRegister)

View File

@@ -4,6 +4,8 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/eolinker/eosc"
"github.com/eolinker/eosc/utils/config" "github.com/eolinker/eosc/utils/config"
) )
@@ -12,7 +14,7 @@ var (
) )
type IClient interface { type IClient interface {
Get(key string) (int64, error) Get(variables eosc.Untyped[string, string]) (int64, error)
} }
type ICounter interface { type ICounter interface {
@@ -24,8 +26,8 @@ type ICounter interface {
RollBack(count int64) error RollBack(count int64) error
} }
func GetRemainCount(client IClient, key string, count int64) (int64, error) { func GetRemainCount(client IClient, key string, count int64, variables eosc.Untyped[string, string]) (int64, error) {
remain, err := client.Get(key) remain, err := client.Get(variables)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@@ -1,18 +1,19 @@
package http package http
import ( import (
"bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"time"
scope_manager "github.com/eolinker/apinto/scope-manager" "github.com/ohler55/ojg/oj"
"github.com/ohler55/ojg/jp" "github.com/ohler55/ojg/jp"
scope_manager "github.com/eolinker/apinto/scope-manager"
"github.com/eolinker/apinto/drivers" "github.com/eolinker/apinto/drivers"
"github.com/eolinker/apinto/drivers/counter" "github.com/eolinker/apinto/drivers/counter"
"github.com/ohler55/ojg/oj"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
"github.com/eolinker/eosc" "github.com/eolinker/eosc"
@@ -23,8 +24,12 @@ var _ eosc.IWorker = (*Executor)(nil)
type Executor struct { type Executor struct {
drivers.WorkerBase drivers.WorkerBase
request *fasthttp.Request req *fasthttp.Request
expr jp.Expr contentType string
query map[string]string
header map[string]string
body map[string]string
expr jp.Expr
} }
func (b *Executor) Start() error { func (b *Executor) Start() error {
@@ -48,32 +53,20 @@ func (b *Executor) reset(conf *Config) error {
request := fasthttp.AcquireRequest() request := fasthttp.AcquireRequest()
request.SetRequestURI(conf.URI) request.SetRequestURI(conf.URI)
request.Header.SetMethod(conf.Method) request.Header.SetMethod(conf.Method)
for key, value := range conf.Headers {
request.Header.Set(key, value) b.contentType = conf.ContentType
} b.header = conf.Headers
for key, value := range conf.QueryParam { b.query = conf.QueryParam
request.URI().QueryArgs().Set(key, value) b.body = conf.BodyParam
}
if conf.ContentType == "json" { b.req = request
request.Header.SetContentType("application/json")
body, _ := json.Marshal(conf.BodyParam)
request.SetBody(body)
} else {
request.Header.SetContentType("application/x-www-form-urlencoded")
bodyParams := url.Values{}
for key, value := range conf.BodyParam {
bodyParams.Set(key, value)
}
request.SetBodyString(bodyParams.Encode())
}
b.request = request
b.expr = expr b.expr = expr
scope_manager.Set(b.Id(), b, conf.Scopes...) scope_manager.Set(b.Id(), b, conf.Scopes...)
return nil return nil
} }
func (b *Executor) Stop() error { func (b *Executor) Stop() error {
fasthttp.ReleaseRequest(b.request) fasthttp.ReleaseRequest(b.req)
scope_manager.Del(b.Id()) scope_manager.Del(b.Id())
return nil return nil
} }
@@ -86,21 +79,58 @@ var httpClient = fasthttp.Client{
Name: "apinto-counter", Name: "apinto-counter",
} }
func (b *Executor) Get(key string) (int64, error) { func (b *Executor) Get(variables eosc.Untyped[string, string]) (int64, error) {
req := fasthttp.AcquireRequest() req := fasthttp.AcquireRequest()
b.request.CopyTo(req) b.req.CopyTo(req)
resp := fasthttp.AcquireResponse() resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req) defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
for key, value := range b.header {
v, ok := variables.Get(value)
if !ok {
v = value
}
req.Header.Set(key, v)
}
for key, value := range b.query {
v, ok := variables.Get(value)
if !ok {
v = value
}
req.URI().QueryArgs().Set(key, v)
}
req.URI().SetQueryStringBytes(bytes.Replace(req.URI().QueryString(), []byte("$key"), []byte(key), -1)) var body []byte
req.SetBody(bytes.Replace(req.Body(), []byte("$key"), []byte(key), -1)) switch b.contentType {
case "json":
err := httpClient.Do(req, resp) for key, value := range b.body {
v, ok := variables.Get(value)
if !ok {
v = value
}
b.body[key] = v
}
body, _ = json.Marshal(b.body)
req.Header.SetContentType("application/json")
case "form-data":
params := url.Values{}
for key, value := range b.body {
v, ok := variables.Get(value)
if !ok {
v = value
}
params.Add(key, v)
}
body = []byte(params.Encode())
req.Header.SetContentType("application/x-www-form-urlencoded")
}
req.SetBody(body)
err := httpClient.DoTimeout(req, resp, 10*time.Second)
if err != nil { if err != nil {
return 0, err return 0, err
} }
if resp.StatusCode() != fasthttp.StatusOK { if resp.StatusCode() != fasthttp.StatusOK {
return 0, fmt.Errorf("error http status code: %d,key: %s,id: %s", resp.StatusCode(), key, b.Id()) return 0, fmt.Errorf("http status code is %d", resp.StatusCode())
} }
result, err := oj.Parse(resp.Body()) result, err := oj.Parse(resp.Body())
if err != nil { if err != nil {
@@ -109,10 +139,10 @@ func (b *Executor) Get(key string) (int64, error) {
// 解析JSON // 解析JSON
v := b.expr.Get(result) v := b.expr.Get(result)
if v == nil || len(v) < 1 { if v == nil || len(v) < 1 {
return 0, fmt.Errorf("no found key: %s,id: %s", key, b.Id()) return 0, fmt.Errorf("json path %s not found,id is %d", b.expr.String(), b.Id())
} }
if len(v) != 1 { if len(v) != 1 {
return 0, fmt.Errorf("invalid value: %v,key: %s,id: %s", v, key, b.Id()) return 0, fmt.Errorf("json path %s found more than one,id is %d", b.expr.String(), b.Id())
} }
return v[0].(int64), nil return v[0].(int64), nil
} }

View File

@@ -2,11 +2,12 @@ package kafka
import ( import (
"context" "context"
"sync"
"github.com/Shopify/sarama" "github.com/Shopify/sarama"
"github.com/eolinker/eosc" "github.com/eolinker/eosc"
"github.com/eolinker/eosc/formatter" "github.com/eolinker/eosc/formatter"
"github.com/eolinker/eosc/log" "github.com/eolinker/eosc/log"
"sync"
) )
type Producer interface { type Producer interface {
@@ -88,7 +89,7 @@ func (o *tProducer) output(entry eosc.IEntry) error {
msg.Partition = o.conf.Partition msg.Partition = o.conf.Partition
} }
if o.conf.PartitionType == "hash" { if o.conf.PartitionType == "hash" {
msg.Key = sarama.StringEncoder(entry.Read(o.conf.PartitionKey)) msg.Key = sarama.StringEncoder(eosc.ReadStringFromEntry(entry, o.conf.PartitionKey))
} }
o.write(msg) o.write(msg)

View File

@@ -3,10 +3,11 @@ package nsq
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/eolinker/eosc/log"
"github.com/nsqio/go-nsq"
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/eolinker/eosc/log"
"github.com/nsqio/go-nsq"
) )
const ( const (
@@ -29,7 +30,7 @@ type node struct {
status int status int
} }
//Create // Create
func CreateProducerPool(addrs []string, authSecret string, conf map[string]interface{}) (*producerPool, error) { func CreateProducerPool(addrs []string, authSecret string, conf map[string]interface{}) (*producerPool, error) {
pool := &producerPool{ pool := &producerPool{
@@ -87,7 +88,7 @@ func (p *producerPool) PublishAsync(topic string, body []byte) error {
log.Errorf("log output nsqd is invalid. nsqd_addr:%s error:%s", producerNode.producer.String(), err) log.Errorf("log output nsqd is invalid. nsqd_addr:%s error:%s", producerNode.producer.String(), err)
continue continue
} }
break return
} }
log.Errorf("no available nsqd node. data: %s", fmt.Sprintf("topic:%s data:%s", topic, body)) log.Errorf("no available nsqd node. data: %s", fmt.Sprintf("topic:%s data:%s", topic, body))
}(n) }(n)
@@ -95,7 +96,7 @@ func (p *producerPool) PublishAsync(topic string, body []byte) error {
return nil return nil
} }
//Check 检查节点状态 // Check 检查节点状态
func (p *producerPool) Check() { func (p *producerPool) Check() {
ticker := time.NewTicker(time.Second * 30) ticker := time.NewTicker(time.Second * 30)

View File

@@ -6,13 +6,15 @@ import (
"testing" "testing"
"time" "time"
"github.com/eolinker/eosc"
redis "github.com/go-redis/redis/v8" redis "github.com/go-redis/redis/v8"
) )
type demoClient struct { type demoClient struct {
} }
func (d *demoClient) Get(key string) (int64, error) { func (d *demoClient) Get(variables eosc.Untyped[string, string]) (int64, error) {
return 100, nil return 100, nil
} }

View File

@@ -51,7 +51,7 @@ func (b *executor) DoHttpFilter(ctx http_service.IHttpContext, next eocontext.IC
key := b.keyGenerate.Key(ctx) key := b.keyGenerate.Key(ctx)
ct, has := b.counters.Get(key) ct, has := b.counters.Get(key)
if !has { if !has {
ct = NewRedisCounter(key, b.cache, b.client) ct = NewRedisCounter(key, b.keyGenerate.Variables(ctx), b.cache, b.client)
b.counters.Set(key, ct) b.counters.Set(key, ct)
} }
var count int64 = 1 var count int64 = 1

View File

@@ -4,6 +4,8 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/eolinker/eosc"
http_service "github.com/eolinker/eosc/eocontext/http-context" http_service "github.com/eolinker/eosc/eocontext/http-context"
) )
@@ -11,6 +13,7 @@ var _ IKeyGenerator = (*keyGenerate)(nil)
type IKeyGenerator interface { type IKeyGenerator interface {
Key(ctx http_service.IHttpContext) string Key(ctx http_service.IHttpContext) string
Variables(ctx http_service.IHttpContext) eosc.Untyped[string, string]
} }
func newKeyGenerate(key string) *keyGenerate { func newKeyGenerate(key string) *keyGenerate {
@@ -40,6 +43,15 @@ type keyGenerate struct {
variables []string variables []string
} }
func (k *keyGenerate) Variables(ctx http_service.IHttpContext) eosc.Untyped[string, string] {
variables := eosc.BuildUntyped[string, string]()
entry := ctx.GetEntry()
for _, v := range k.variables {
variables.Set(fmt.Sprintf("$%s", v), eosc.ReadStringFromEntry(entry, v))
}
return variables
}
func (k *keyGenerate) Key(ctx http_service.IHttpContext) string { func (k *keyGenerate) Key(ctx http_service.IHttpContext) string {
variables := make([]interface{}, 0, len(k.variables)) variables := make([]interface{}, 0, len(k.variables))
for _, v := range k.variables { for _, v := range k.variables {

View File

@@ -5,6 +5,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/eolinker/eosc"
scope_manager "github.com/eolinker/apinto/scope-manager" scope_manager "github.com/eolinker/apinto/scope-manager"
"github.com/eolinker/apinto/drivers/counter" "github.com/eolinker/apinto/drivers/counter"
@@ -14,8 +16,8 @@ import (
var _ counter.ICounter = (*LocalCounter)(nil) var _ counter.ICounter = (*LocalCounter)(nil)
func NewLocalCounter(key string, client scope_manager.IProxyOutput[counter.IClient]) *LocalCounter { func NewLocalCounter(key string, variables eosc.Untyped[string, string], client scope_manager.IProxyOutput[counter.IClient]) *LocalCounter {
return &LocalCounter{key: key, client: client} return &LocalCounter{key: key, client: client, variables: variables}
} }
// LocalCounter 本地计数器 // LocalCounter 本地计数器
@@ -28,6 +30,8 @@ type LocalCounter struct {
locker sync.Mutex locker sync.Mutex
variables eosc.Untyped[string, string]
resetTime time.Time resetTime time.Time
client scope_manager.IProxyOutput[counter.IClient] client scope_manager.IProxyOutput[counter.IClient]
@@ -47,7 +51,7 @@ func (c *LocalCounter) Lock(count int64) error {
c.resetTime = now c.resetTime = now
for _, client := range c.client.List() { for _, client := range c.client.List() {
// 获取最新的次数 // 获取最新的次数
remain, err = counter.GetRemainCount(client, c.key, count) remain, err = counter.GetRemainCount(client, c.key, count, c.variables)
if err != nil { if err != nil {
log.Errorf("get remain count error: %s", err.Error()) log.Errorf("get remain count error: %s", err.Error())
continue continue

View File

@@ -7,6 +7,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/eolinker/eosc"
scope_manager "github.com/eolinker/apinto/scope-manager" scope_manager "github.com/eolinker/apinto/scope-manager"
"github.com/eolinker/apinto/resources" "github.com/eolinker/apinto/resources"
@@ -33,19 +35,22 @@ type RedisCounter struct {
lockerKey string lockerKey string
lockKey string lockKey string
remainKey string remainKey string
variables eosc.Untyped[string, string]
} }
func NewRedisCounter(key string, redis scope_manager.IProxyOutput[resources.ICache], client scope_manager.IProxyOutput[counter.IClient]) *RedisCounter { func NewRedisCounter(key string, variables eosc.Untyped[string, string], redis scope_manager.IProxyOutput[resources.ICache], client scope_manager.IProxyOutput[counter.IClient]) *RedisCounter {
return &RedisCounter{ return &RedisCounter{
key: key, key: key,
redis: redis, redis: redis,
client: client, client: client,
localCounter: NewLocalCounter(key, client), localCounter: NewLocalCounter(key, variables, client),
ctx: context.Background(), ctx: context.Background(),
lockerKey: fmt.Sprintf("%s:locker", key), lockerKey: fmt.Sprintf("%s:locker", key),
lockKey: fmt.Sprintf("%s:lock", key), lockKey: fmt.Sprintf("%s:lock", key),
remainKey: fmt.Sprintf("%s:remain", key), remainKey: fmt.Sprintf("%s:remain", key),
variables: variables,
} }
} }
@@ -110,7 +115,7 @@ func (r *RedisCounter) lock(cache resources.ICache, count int64) error {
} }
lock, _ := strconv.ParseInt(lockCount, 10, 64) lock, _ := strconv.ParseInt(lockCount, 10, 64)
for _, client := range r.client.List() { for _, client := range r.client.List() {
remain, err = counter.GetRemainCount(client, r.key, count+lock) remain, err = counter.GetRemainCount(client, r.key, count+lock, r.variables)
if err != nil { if err != nil {
log.Errorf("get remain count error: %s", err) log.Errorf("get remain count error: %s", err)
continue continue

View File

@@ -0,0 +1,24 @@
package data_transform
import (
"github.com/eolinker/apinto/drivers"
"github.com/eolinker/eosc"
)
type Config struct {
RequestTransform bool `json:"request_transform" label:"请求转换"`
ResponseTransform bool `json:"response_transform" label:"响应转换"`
XMLRootTag string `json:"xml_root_tag" label:"XML根标签"`
XMLDeclaration map[string]string `json:"xml_declaration" label:"XML声明"`
ErrorType string `json:"error_type" label:"报错数据类型" default:"json" enum:"json,xml"`
}
func Create(id, name string, conf *Config, workers map[eosc.RequireId]eosc.IWorker) (eosc.IWorker, error) {
bc := &executor{
WorkerBase: drivers.Worker(id, name),
conf: conf,
}
return bc, nil
}

View File

@@ -0,0 +1,111 @@
package data_transform
import (
"mime"
"net/http"
"strings"
"github.com/eolinker/eosc/log"
"github.com/eolinker/apinto/drivers"
"github.com/eolinker/eosc"
"github.com/eolinker/eosc/eocontext"
http_service "github.com/eolinker/eosc/eocontext/http-context"
)
var _ http_service.HttpFilter = (*executor)(nil)
var _ eocontext.IFilter = (*executor)(nil)
type executor struct {
drivers.WorkerBase
conf *Config
}
func (b *executor) DoFilter(ctx eocontext.EoContext, next eocontext.IChain) (err error) {
return http_service.DoHttpFilter(b, ctx, next)
}
func (b *executor) DoHttpFilter(ctx http_service.IHttpContext, next eocontext.IChain) error {
if b.conf.RequestTransform && (ctx.Proxy().Method() == http.MethodPost || ctx.Proxy().Method() == http.MethodPut || ctx.Proxy().Method() == http.MethodPatch) {
// 对请求体做转换
body, _ := ctx.Proxy().Body().RawBody()
contentType, _, _ := mime.ParseMediaType(ctx.Request().ContentType())
if strings.Contains(contentType, "/json") {
result, err := json2xml(body, b.conf.XMLRootTag, b.conf.XMLDeclaration)
if err != nil {
errInfo := "fail to transform request json to xml"
ctx.Response().SetStatus(http.StatusBadRequest, "400")
ctx.Response().SetBody([]byte(encode(b.conf.ErrorType, errInfo, http.StatusBadRequest)))
log.Errorf("%s,body is %s", errInfo, string(body))
return err
}
ctx.Proxy().Body().SetRaw("application/xml", result)
} else if strings.Contains(contentType, "/xml") {
result, err := xml2json(body, b.conf.XMLDeclaration)
if err != nil {
errInfo := "fail to transform request xml to json"
ctx.Response().SetStatus(http.StatusBadRequest, "400")
ctx.Response().SetBody([]byte(encode(b.conf.ErrorType, errInfo, http.StatusBadRequest)))
log.Errorf("%s,body is %s", errInfo, string(body))
return err
}
ctx.Proxy().Body().SetRaw("application/json", result)
}
}
err := next.DoChain(ctx)
if err != nil {
return err
}
if b.conf.ResponseTransform {
// 对请求体做转换
body := ctx.Response().GetBody()
contentType, _, _ := mime.ParseMediaType(ctx.Response().ContentType())
if strings.Contains(contentType, "/json") {
result, err := json2xml(body, b.conf.XMLRootTag, b.conf.XMLDeclaration)
if err != nil {
errInfo := "fail to transform response json to xml"
ctx.Response().SetStatus(http.StatusBadRequest, "400")
ctx.Response().SetBody([]byte(encode(b.conf.ErrorType, errInfo, http.StatusBadRequest)))
log.Errorf("%s,body is %s", errInfo, string(body))
return err
}
ctx.Response().SetBody(result)
ctx.Response().Headers().Set("Content-Type", "application/xml")
} else if strings.Contains(contentType, "/xml") {
result, err := xml2json(body, b.conf.XMLDeclaration)
if err != nil {
errInfo := "fail to transform response xml to json"
ctx.Response().SetStatus(http.StatusBadRequest, "400")
ctx.Response().SetBody([]byte(encode(b.conf.ErrorType, errInfo, http.StatusBadRequest)))
log.Errorf("%s,body is %s", errInfo, string(body))
return err
}
ctx.Response().SetBody(result)
ctx.Response().Headers().Set("Content-Type", "application/json")
}
}
return nil
}
func (b *executor) Start() error {
return nil
}
func (b *executor) Reset(conf interface{}, workers map[eosc.RequireId]eosc.IWorker) error {
return nil
}
func (b *executor) Stop() error {
b.Destroy()
return nil
}
func (b *executor) Destroy() {
b.conf = nil
return
}
func (b *executor) CheckSkill(skill string) bool {
return http_service.FilterSkillName == skill
}

View File

@@ -0,0 +1,18 @@
package data_transform
import (
"github.com/eolinker/apinto/drivers"
"github.com/eolinker/eosc"
)
const (
Name = "data_transform"
)
func Register(register eosc.IExtenderDriverRegister) {
register.RegisterExtenderDriver(Name, NewFactory())
}
func NewFactory() eosc.IExtenderDriverFactory {
return drivers.NewFactory[Config](Create)
}

View File

@@ -0,0 +1,100 @@
package data_transform
import (
"encoding/json"
"fmt"
"strings"
. "github.com/clbanning/mxj"
)
var declarations = []string{"version", "encoding", "standalone"}
func xml2json(xmlVal []byte, xmlDeclaration map[string]string) ([]byte, error) {
m, err := NewMapXml(xmlVal)
if err != nil {
return nil, err
}
for _, key := range declarations {
if _, ok := m[key]; !ok {
if xmlDeclaration != nil {
if v, has := xmlDeclaration[key]; has {
m[key] = v
}
}
}
if v, ok := m[key]; ok {
vv, success := v.(string)
if success {
m[key] = strings.Replace(vv, `"`, "", -1)
}
}
}
jsonObject, err := m.Json()
if err != nil {
return nil, err
}
return jsonObject, nil
}
func json2xml(jsonVal []byte, rootTag string, xd map[string]string) ([]byte, error) {
var m, n map[string]interface{}
if err := json.Unmarshal(jsonVal, &m); err != nil {
return nil, err
}
n = make(map[string]interface{})
for _, key := range declarations {
if v, ok := m[key]; ok {
n[key] = v
delete(m, key)
} else {
if xd != nil {
if v, ok := xd[key]; ok {
n[key] = v
}
}
}
}
var x []byte
var err error
x, err = Map(m).XmlIndent("", " ", rootTag)
if err != nil {
return x, err
}
declaration := xmlDeclaration(n)
retBody := []byte(fmt.Sprintf("%s\r\n%s", declaration, string(x)))
return retBody, nil
}
func xmlDeclaration(m map[string]interface{}) string {
declaration := ""
for _, a := range declarations {
if declaration == "" {
declaration = "<?xml"
}
if v, ok := m[a]; ok {
delete(m, a)
declaration += fmt.Sprintf(` %s="%s"`, a, v)
}
}
if declaration != "" {
declaration += "?>"
}
return declaration
}
func encode(ent string, origin string, statusCode int) string {
if ent == "json" {
tmp := map[string]interface{}{
"message": origin,
"status_code": statusCode,
}
body, _ := json.Marshal(tmp)
return string(body)
}
return origin
}

View File

@@ -5,6 +5,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/eolinker/eosc"
dynamic_params "github.com/eolinker/apinto/drivers/plugins/extra-params_v2/dynamic-params" dynamic_params "github.com/eolinker/apinto/drivers/plugins/extra-params_v2/dynamic-params"
http_service "github.com/eolinker/eosc/eocontext/http-context" http_service "github.com/eolinker/eosc/eocontext/http-context"
) )
@@ -124,7 +126,7 @@ func (b *paramInfo) Build(ctx http_service.IHttpContext, contentType string, par
func (b *paramInfo) build(ctx http_service.IHttpContext, contentType string, params interface{}) (string, error) { func (b *paramInfo) build(ctx http_service.IHttpContext, contentType string, params interface{}) (string, error) {
if b.driver == nil { if b.driver == nil {
if b.systemValue { if b.systemValue {
return ctx.GetLabel(b.value), nil return eosc.ReadStringFromEntry(ctx.GetEntry(), b.value), nil
} }
return b.value, nil return b.value, nil
} }

View File

@@ -6,6 +6,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/eolinker/eosc"
http_service "github.com/eolinker/eosc/eocontext/http-context" http_service "github.com/eolinker/eosc/eocontext/http-context"
"github.com/ohler55/ojg/jp" "github.com/ohler55/ojg/jp"
"github.com/ohler55/ojg/oj" "github.com/ohler55/ojg/oj"
@@ -166,7 +168,7 @@ func retrieveParam(ctx http_service.IHttpContext, contentType string, body inter
} }
} }
case positionSystem: case positionSystem:
return ctx.GetLabel(value.key) return eosc.ReadStringFromEntry(ctx.GetEntry(), value.key)
} }
return "" return ""
} }

View File

@@ -21,8 +21,7 @@ const (
var ( var (
paramPositionErrInfo = `[plugin extra-params config err] param position must be in the set ["query","header",body]. err position: %s ` paramPositionErrInfo = `[plugin extra-params config err] param position must be in the set ["query","header",body]. err position: %s `
//parseBodyErrInfo = `[extra_params] Fail to parse body! [err]: %s` paramNameErrInfo = `[plugin extra-params config err] param name must be not null. `
paramNameErrInfo = `[plugin extra-params config err] param name must be not null. `
) )
func encodeErr(ent string, origin string, statusCode int) error { func encodeErr(ent string, origin string, statusCode int) error {
@@ -36,176 +35,3 @@ func encodeErr(ent string, origin string, statusCode int) error {
} }
return errors.New(origin) return errors.New(origin)
} }
//func parseBodyParams(ctx http_service.IHttpContext) (interface{}, url.Values, error) {
// if ctx.Proxy().Method() != http.MethodPost && ctx.Proxy().Method() != http.MethodPut && ctx.Proxy().Method() != http.MethodPatch {
// return nil, nil, nil
// }
// contentType, _, _ := mime.ParseMediaType(ctx.Proxy().Body().ContentType())
// switch contentType {
// case http_context.FormData, http_context.MultipartForm:
// formParams, err := ctx.Proxy().Body().BodyForm()
// if err != nil {
// return nil, nil, err
// }
// return nil, formParams, nil
// case http_context.JSON:
// body, err := ctx.Proxy().Body().RawBody()
// if err != nil {
// return nil, nil, err
// }
// if string(body) == "" {
// body = []byte("{}")
// }
// bodyParams, err := oj.Parse(body)
// return bodyParams, nil, err
// }
// return nil, nil, errors.New("unsupported content-type: " + contentType)
//}
//
//func parseBodyParams(ctx http_service.IHttpContext) (map[string]interface{}, map[string][]string, error) {
// contentType, _, _ := mime.ParseMediaType(ctx.Proxy().Body().ContentType())
//
// switch contentType {
// case http_context.FormData, http_context.MultipartForm:
// formParams, err := ctx.Proxy().Body().BodyForm()
// if err != nil {
// return nil, nil, err
// }
// return nil, formParams, nil
// case http_context.JSON:
// body, err := ctx.Proxy().Body().RawBody()
// if err != nil {
// return nil, nil, err
// }
// var bodyParams map[string]interface{}
// err = json.Unmarshal(body, &bodyParams)
// if err != nil {
// return bodyParams, nil, err
// }
// }
// return nil, nil, errors.New("[params_transformer] unsupported content-type: " + contentType)
//}
//func getHeaderValue(headers map[string][]string, param *ExtraParam, value string) (string, error) {
// paramName := ConvertHeaderKey(param.Name)
//
// if param.Conflict == "" {
// param.Conflict = paramConvert
// }
//
// var paramValue string
//
// if _, ok := headers[paramName]; !ok {
// param.Conflict = paramConvert
// } else {
// paramValue = headers[paramName][0]
// }
//
// if param.Conflict == paramConvert {
// paramValue = value
// } else if param.Conflict == paramError {
// errInfo := `[extra_params] "` + param.Name + `" has a conflict.`
// return "", errors.New(errInfo)
// }
//
// return paramValue, nil
//}
//func hasQueryValue(rawQuery string, paramName string) bool {
// bytes := []byte(rawQuery)
// if len(bytes) == 0 {
// return false
// }
//
// k := 0
// for i, c := range bytes {
// switch c {
// case '=':
// key := string(bytes[k:i])
// if key == paramName {
// return true
// }
// case '&':
// k = i + 1
// }
// }
//
// return false
//}
//func getQueryValue(ctx http_service.IHttpContext, param *ExtraParam, value string) (string, error) {
// paramValue := ""
// if param.Conflict == "" {
// param.Conflict = paramConvert
// }
//
// //判断请求中是否包含对应的query参数
// if !hasQueryValue(ctx.Proxy().URI().RawQuery(), param.Name) {
// param.Conflict = paramConvert
// } else {
// paramValue = ctx.Proxy().URI().GetQuery(param.Name)
// }
//
// if param.Conflict == paramConvert {
// paramValue = value
// } else if param.Conflict == paramError {
// errInfo := `[extra_params] "` + param.Name + `" has a conflict.`
// return "", errors.New(errInfo)
// }
//
// return paramValue, nil
//}
//
//func getBodyValue(bodyParams map[string]interface{}, formParams map[string][]string, param *ExtraParam, contentType string, value interface{}) (interface{}, error) {
// var paramValue interface{} = nil
// Conflict := param.Conflict
// if Conflict == "" {
// Conflict = paramConvert
// }
// if strings.Contains(contentType, http_context.FormData) || strings.Contains(contentType, http_context.MultipartForm) {
// if _, ok := formParams[param.Name]; !ok {
// Conflict = paramConvert
// } else {
// paramValue = formParams[param.Name][0]
// }
// } else if strings.Contains(contentType, http_context.JSON) {
// if _, ok := bodyParams[param.Name]; !ok {
// param.Conflict = paramConvert
// } else {
// paramValue = bodyParams[param.Name]
// }
// }
// if Conflict == paramConvert {
// paramValue = value
// } else if Conflict == paramError {
// errInfo := `[extra_params] "` + param.Name + `" has a conflict.`
// return "", errors.New(errInfo)
// }
//
// return paramValue, nil
//}
//func ConvertHeaderKey(header string) string {
// header = strings.ToLower(header)
// headerArray := strings.Split(header, "-")
// h := ""
// arrLen := len(headerArray)
// for i, value := range headerArray {
// vLen := len(value)
// if vLen < 1 {
// continue
// } else {
// if vLen == 1 {
// h += strings.ToUpper(value)
// } else {
// h += strings.ToUpper(string(value[0])) + value[1:]
// }
// if i != arrLen-1 {
// h += "-"
// }
// }
// }
// return h
//}

View File

@@ -8,15 +8,16 @@ import (
type Config struct { type Config struct {
Listen int `json:"listen" yaml:"listen" title:"port" description:"使用端口" default:"80" label:"端口号" maximum:"65535"` Listen int `json:"listen" yaml:"listen" title:"port" description:"使用端口" default:"80" label:"端口号" maximum:"65535"`
ServiceName string `json:"service_name" yaml:"service_name" label:"服务名"` ServiceName string `json:"service_name" yaml:"service_name" label:"服务名"`
MethodName string `json:"method_name" yaml:"method_name" label:"方法名"` MethodName string `json:"method_name" yaml:"method_name" label:"方法名"`
Rules []Rule `json:"rules" yaml:"rules" label:"路由规则"` Rules []Rule `json:"rules" yaml:"rules" label:"路由规则"`
Service eosc.RequireId `json:"service" yaml:"service" skill:"github.com/eolinker/apinto/service.service.IService" required:"true" label:"目标服务"` Service eosc.RequireId `json:"service" yaml:"service" skill:"github.com/eolinker/apinto/service.service.IService" required:"true" label:"目标服务"`
Template eosc.RequireId `json:"template" yaml:"template" skill:"github.com/eolinker/apinto/template.template.ITemplate" required:"false" label:"插件模版"` Template eosc.RequireId `json:"template" yaml:"template" skill:"github.com/eolinker/apinto/template.template.ITemplate" required:"false" label:"插件模版"`
Disable bool `json:"disable" yaml:"disable" label:"禁用路由"` Disable bool `json:"disable" yaml:"disable" label:"禁用路由"`
Plugins plugin.Plugins `json:"plugins" yaml:"plugins" label:"插件配置"` Plugins plugin.Plugins `json:"plugins" yaml:"plugins" label:"插件配置"`
Retry int `json:"retry" label:"重试次数" yaml:"retry"` Retry int `json:"retry" label:"重试次数" yaml:"retry"`
TimeOut int `json:"time_out" label:"超时时间"` TimeOut int `json:"time_out" label:"超时时间"`
Labels map[string]string `json:"labels" label:"路由标签"`
} }
// Rule 规则 // Rule 规则

View File

@@ -26,6 +26,7 @@ type dubboHandler struct {
filters eocontext.IChainPro filters eocontext.IChainPro
retry int retry int
timeout time.Duration timeout time.Duration
labels map[string]string
} }
var completeCaller = manager.NewCompleteCaller() var completeCaller = manager.NewCompleteCaller()
@@ -41,6 +42,9 @@ func (d *dubboHandler) ServeHTTP(ctx eocontext.EoContext) {
dubboCtx.Response().SetBody(manager.Dubbo2ErrorResult(errors.New("router disable"))) dubboCtx.Response().SetBody(manager.Dubbo2ErrorResult(errors.New("router disable")))
return return
} }
for key, value := range d.labels {
ctx.SetLabel(key, value)
}
//set retry timeout //set retry timeout
ctx.WithValue(ctx_key.CtxKeyRetry, d.retry) ctx.WithValue(ctx_key.CtxKeyRetry, d.retry)

View File

@@ -10,15 +10,16 @@ type Config struct {
Host []string `json:"host" yaml:"host" label:"域名"` Host []string `json:"host" yaml:"host" label:"域名"`
ServiceName string `json:"service_name" yaml:"service_name" label:"服务名"` ServiceName string `json:"service_name" yaml:"service_name" label:"服务名"`
MethodName string `json:"method_name" yaml:"method_name" label:"方法名"` MethodName string `json:"method_name" yaml:"method_name" label:"方法名"`
Rules []Rule `json:"rules" yaml:"rules" label:"路由规则"` Rules []Rule `json:"rules" yaml:"rules" label:"路由规则"`
Service eosc.RequireId `json:"service" yaml:"service" skill:"github.com/eolinker/apinto/service.service.IService" required:"true" label:"目标服务"` Service eosc.RequireId `json:"service" yaml:"service" skill:"github.com/eolinker/apinto/service.service.IService" required:"true" label:"目标服务"`
Template eosc.RequireId `json:"template" yaml:"template" skill:"github.com/eolinker/apinto/template.template.ITemplate" required:"false" label:"插件模版"` Template eosc.RequireId `json:"template" yaml:"template" skill:"github.com/eolinker/apinto/template.template.ITemplate" required:"false" label:"插件模版"`
Disable bool `json:"disable" yaml:"disable" label:"禁用路由"` Disable bool `json:"disable" yaml:"disable" label:"禁用路由"`
Plugins plugin.Plugins `json:"plugins" yaml:"plugins" label:"插件配置"` Plugins plugin.Plugins `json:"plugins" yaml:"plugins" label:"插件配置"`
Retry int `json:"retry" label:"重试次数" yaml:"retry"` Retry int `json:"retry" label:"重试次数" yaml:"retry"`
TimeOut int `json:"time_out" label:"超时时间"` TimeOut int `json:"time_out" label:"超时时间"`
Labels map[string]string `json:"labels" label:"路由标签"`
} }
// Rule 规则 // Rule 规则

View File

@@ -27,6 +27,7 @@ type grpcRouter struct {
filters eocontext.IChainPro filters eocontext.IChainPro
disable bool disable bool
retry int retry int
labels map[string]string
timeout time.Duration timeout time.Duration
} }
@@ -40,6 +41,9 @@ func (h *grpcRouter) ServeHTTP(ctx eocontext.EoContext) {
grpcContext.FastFinish() grpcContext.FastFinish()
return return
} }
for key, value := range h.labels {
ctx.SetLabel(key, value)
}
//set retry timeout //set retry timeout
ctx.WithValue(ctx_key.CtxKeyRetry, h.retry) ctx.WithValue(ctx_key.CtxKeyRetry, h.retry)

View File

@@ -58,6 +58,7 @@ func (h *GrpcRouter) reset(cfg *Config, workers map[eosc.RequireId]eosc.IWorker)
retry: cfg.Retry, retry: cfg.Retry,
timeout: time.Duration(cfg.TimeOut) * time.Millisecond, timeout: time.Duration(cfg.TimeOut) * time.Millisecond,
disable: cfg.Disable, disable: cfg.Disable,
labels: cfg.Labels,
} }
if !cfg.Disable { if !cfg.Disable {

View File

@@ -22,8 +22,9 @@ type Config struct {
Disable bool `json:"disable" yaml:"disable" label:"禁用路由"` Disable bool `json:"disable" yaml:"disable" label:"禁用路由"`
Plugins plugin.Plugins `json:"plugins" yaml:"plugins" label:"插件配置"` Plugins plugin.Plugins `json:"plugins" yaml:"plugins" label:"插件配置"`
Retry int `json:"retry" label:"重试次数" yaml:"retry" switch:"service!==''"` Retry int `json:"retry" label:"重试次数" yaml:"retry" switch:"service!==''"`
TimeOut int `json:"time_out" label:"超时时间" switch:"service!==''"` TimeOut int `json:"time_out" label:"超时时间" switch:"service!==''"`
Labels map[string]string `json:"labels" label:"路由标签"`
} }
// Rule 规则 // Rule 规则

View File

@@ -29,9 +29,9 @@ type httpHandler struct {
filters eocontext.IChainPro filters eocontext.IChainPro
disable bool disable bool
websocket bool websocket bool
labels map[string]string
retry int retry int
timeout time.Duration timeout time.Duration
} }
func (h *httpHandler) ServeHTTP(ctx eocontext.EoContext) { func (h *httpHandler) ServeHTTP(ctx eocontext.EoContext) {
@@ -55,6 +55,11 @@ func (h *httpHandler) ServeHTTP(ctx eocontext.EoContext) {
} }
ctx = wsCtx ctx = wsCtx
} }
for key, value := range h.labels {
// 设置标签
ctx.SetLabel(key, value)
}
//set retry timeout //set retry timeout
ctx.WithValue(ctx_key.CtxKeyRetry, h.retry) ctx.WithValue(ctx_key.CtxKeyRetry, h.retry)
ctx.WithValue(ctx_key.CtxKeyTimeout, h.timeout) ctx.WithValue(ctx_key.CtxKeyTimeout, h.timeout)

View File

@@ -61,6 +61,7 @@ func (h *HttpRouter) reset(cfg *Config, workers map[eosc.RequireId]eosc.IWorker)
disable: cfg.Disable, disable: cfg.Disable,
websocket: cfg.Websocket, websocket: cfg.Websocket,
retry: cfg.Retry, retry: cfg.Retry,
labels: cfg.Labels,
timeout: time.Duration(cfg.TimeOut) * time.Millisecond, timeout: time.Duration(cfg.TimeOut) * time.Millisecond,
} }

View File

@@ -21,7 +21,7 @@ func NewEntry(ctx http_service.IHttpContext) *Entry {
return &Entry{ctx: ctx} return &Entry{ctx: ctx}
} }
func (e *Entry) Read(pattern string) string { func (e *Entry) Read(pattern string) interface{} {
v, ok := rule.Read(pattern, e.ctx) v, ok := rule.Read(pattern, e.ctx)
if !ok { if !ok {
return "" return ""
@@ -50,7 +50,7 @@ type ChildEntry struct {
childReader IReaderIndex childReader IReaderIndex
} }
func (c *ChildEntry) Read(pattern string) string { func (c *ChildEntry) Read(pattern string) interface{} {
if strings.HasPrefix(pattern, c.pre) { if strings.HasPrefix(pattern, c.pre) {
name := strings.TrimPrefix(pattern, c.pre) name := strings.TrimPrefix(pattern, c.pre)
v, _ := c.childReader.ReadByIndex(c.index, name, c.parent.ctx) v, _ := c.childReader.ReadByIndex(c.index, name, c.parent.ctx)

View File

@@ -1,15 +1,44 @@
package http_entry package http_entry
import ( import (
"strconv"
http_service "github.com/eolinker/eosc/eocontext/http-context" http_service "github.com/eolinker/eosc/eocontext/http-context"
) )
type IProxyReader interface { type IProxyReader interface {
ReadProxy(name string, proxy http_service.IProxy) (string, bool) ReadProxy(name string, proxy http_service.IProxy) (interface{}, bool)
} }
type ProxyReadFunc func(name string, proxy http_service.IProxy) (string, bool) func ReadProxyFromProxyReader(reader IProxyReader, proxy http_service.IProxy, key string) (string, bool) {
var data string
value, has := reader.ReadProxy(key, proxy)
if !has {
return "", false
}
switch v := value.(type) {
case string:
data = v
case []byte:
data = string(v)
case int:
data = strconv.Itoa(v)
case int64:
data = strconv.FormatInt(v, 10)
case float32:
data = strconv.FormatFloat(float64(v), 'f', -1, 32)
case float64:
data = strconv.FormatFloat(v, 'f', -1, 64)
case bool:
data = strconv.FormatBool(v)
default:
return "", false
}
return data, true
}
func (p ProxyReadFunc) ReadProxy(name string, proxy http_service.IProxy) (string, bool) { type ProxyReadFunc func(name string, proxy http_service.IProxy) (interface{}, bool)
func (p ProxyReadFunc) ReadProxy(name string, proxy http_service.IProxy) (interface{}, bool) {
return p(name, proxy) return p(name, proxy)
} }

View File

@@ -7,16 +7,12 @@ import (
) )
type IReaderIndex interface { type IReaderIndex interface {
ReadByIndex(index int, name string, ctx http_service.IHttpContext) (string, bool) ReadByIndex(index int, name string, ctx http_service.IHttpContext) (interface{}, bool)
} }
type ProxyReaders map[string]IProxyReader type ProxyReaders map[string]IProxyReader
func (p ProxyReaders) ReadByIndex(index int, name string, ctx http_service.IHttpContext) (string, bool) { func (p ProxyReaders) ReadByIndex(index int, name string, ctx http_service.IHttpContext) (interface{}, bool) {
v, ok := p[name]
if !ok {
return "", false
}
proxies := ctx.Proxies() proxies := ctx.Proxies()
proxyLen := len(proxies) proxyLen := len(proxies)
@@ -26,12 +22,22 @@ func (p ProxyReaders) ReadByIndex(index int, name string, ctx http_service.IHttp
if index == -1 { if index == -1 {
index = proxyLen - 1 index = proxyLen - 1
} }
v, ok := p[name]
return v.ReadProxy(name, proxies[index]) if !ok {
fs := strings.SplitN(name, "_", 2)
if len(fs) == 2 {
v, ok = p[fs[0]]
if ok {
return v.ReadProxy(fs[1], proxies[index])
}
}
return "", false
}
return v.ReadProxy("", proxies[index])
} }
func (p ProxyReaders) Read(name string, ctx http_service.IHttpContext) (string, bool) { func (p ProxyReaders) Read(name string, ctx http_service.IHttpContext) (interface{}, bool) {
ns := strings.SplitN(name, "_", 2) ns := strings.SplitN(name, "_", 2)
v, ok := p[ns[0]] v, ok := p[ns[0]]
if !ok { if !ok {

View File

@@ -2,6 +2,7 @@ package http_entry
import ( import (
"net/url" "net/url"
"os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -9,24 +10,22 @@ import (
"github.com/eolinker/apinto/utils/version" "github.com/eolinker/apinto/utils/version"
"github.com/eolinker/apinto/utils" "github.com/eolinker/apinto/utils"
eosc_utils "github.com/eolinker/eosc/utils"
http_service "github.com/eolinker/eosc/eocontext/http-context" http_service "github.com/eolinker/eosc/eocontext/http-context"
) )
type IReader interface { type IReader interface {
Read(name string, ctx http_service.IHttpContext) (string, bool) Read(name string, ctx http_service.IHttpContext) (interface{}, bool)
} }
type ReadFunc func(name string, ctx http_service.IHttpContext) (string, bool) type ReadFunc func(name string, ctx http_service.IHttpContext) (interface{}, bool)
func (f ReadFunc) Read(name string, ctx http_service.IHttpContext) (string, bool) { func (f ReadFunc) Read(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return f(name, ctx) return f(name, ctx)
} }
type Fields map[string]IReader type Fields map[string]IReader
func (f Fields) Read(name string, ctx http_service.IHttpContext) (string, bool) { func (f Fields) Read(name string, ctx http_service.IHttpContext) (interface{}, bool) {
r, has := f[name] r, has := f[name]
if has { if has {
return r.Read("", ctx) return r.Read("", ctx)
@@ -43,191 +42,203 @@ func (f Fields) Read(name string, ctx http_service.IHttpContext) (string, bool)
if label != "" { if label != "" {
return label, true return label, true
} }
label = os.Getenv(name)
return "", false return label, label != ""
} }
var ( var (
rule Fields = map[string]IReader{ rule Fields = map[string]IReader{
"request_id": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "request_id": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.RequestId(), true return ctx.RequestId(), true
}), }),
"node": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "node": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
if value := ctx.GetLabel(name); value != "" { return os.Getenv("node_id"), true
return value, true
}
globalLabels := eosc_utils.GlobalLabelGet()
return globalLabels["node_id"], true
}), }),
"cluster": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "cluster": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
if value := ctx.GetLabel(name); value != "" { return os.Getenv("cluster_id"), true
return value, true
}
globalLabels := eosc_utils.GlobalLabelGet()
return globalLabels["cluster_id"], true
}), }),
"api_id": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "api_id": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.GetLabel("api_id"), true return ctx.GetLabel("api_id"), true
}), }),
"query": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "query": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
if name == "" { if name == "" {
return utils.QueryUrlEncode(ctx.Request().URI().RawQuery()), true return utils.QueryUrlEncode(ctx.Request().URI().RawQuery()), true
} }
return url.QueryEscape(ctx.Request().URI().GetQuery(name)), true return url.QueryEscape(ctx.Request().URI().GetQuery(name)), true
}), }),
"uri": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "uri": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
//不带请求参数的uri //不带请求参数的uri
return ctx.Request().URI().Path(), true return ctx.Request().URI().Path(), true
}), }),
"content_length": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "content_length": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Request().Header().GetHeader("content-length"), true return ctx.Request().Header().GetHeader("content-length"), true
}), }),
"content_type": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "content_type": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Request().Header().GetHeader("content-type"), true return ctx.Request().Header().GetHeader("content-type"), true
}), }),
"cookie": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "cookie": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
if name == "" { if name == "" {
return ctx.Request().Header().GetHeader("cookie"), true return ctx.Request().Header().GetHeader("cookie"), true
} }
return ctx.Request().Header().GetCookie(name), false return ctx.Request().Header().GetCookie(name), false
}), }),
"msec": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "msec": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return strconv.FormatInt(time.Now().Unix(), 10), true return ctx.AcceptTime().UnixMilli(), true
}), }),
"apinto_version": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "apinto_version": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return version.Version, true return version.Version, true
}), }),
"remote_addr": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "remote_addr": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Request().RemoteAddr(), true return ctx.Request().RemoteAddr(), true
}), }),
"remote_port": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "remote_port": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Request().RemotePort(), true return ctx.Request().RemotePort(), true
}), }),
"request": Fields{ "request": Fields{
"body": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "body": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
body, err := ctx.Request().Body().RawBody() body, err := ctx.Request().Body().RawBody()
if err != nil { if err != nil {
return "", false return "", false
} }
return string(body), true return string(body), true
}), }),
"length": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "length": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return strconv.Itoa(len(ctx.Request().String())), true return ctx.Request().ContentLength(), true
}), }),
"method": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "method": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Request().Method(), true return ctx.Request().Method(), true
}), }),
"time": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "time": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
requestTime := ctx.Value("request_time") requestTime := ctx.Value("request_time")
start, ok := requestTime.(time.Time) start, ok := requestTime.(time.Time)
if !ok { if !ok {
return "", false return "", false
} }
return strconv.FormatInt(time.Now().Sub(start).Milliseconds(), 10), true return time.Now().Sub(start).Milliseconds(), true
}), }),
"uri": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "uri": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Request().URI().RequestURI(), true return ctx.Request().URI().RequestURI(), true
}), }),
}, },
"scheme": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "scheme": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Request().URI().Scheme(), true return ctx.Request().URI().Scheme(), true
}), }),
"status": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "status": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Response().Status(), true return ctx.Response().StatusCode(), true
}), }),
"time_iso8601": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "time_iso8601": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
//带毫秒的ISO-8601时间格式 //带毫秒的ISO-8601时间格式
return time.Now().Format("2006-01-02T15:04:05.000Z07:00"), true //return time.Now().Format("2006-01-02T15:04:05.000Z07:00"), true
return ctx.AcceptTime().Format("2006-01-02T15:04:05.000Z07:00"), true
}), }),
"time_local": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "time_local": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return time.Now().Format("2006-01-02 15:04:05"), true //return time.Now().Format("2006-01-02 15:04:05"), true
return ctx.AcceptTime().Format("2006-01-02 15:04:05"), true
}), }),
"header": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "header": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
if name == "" { if name == "" {
return url.Values(ctx.Request().Header().Headers()).Encode(), true return url.Values(ctx.Request().Header().Headers()).Encode(), true
} }
return ctx.Request().Header().GetHeader(strings.Replace(name, "_", "-", -1)), true return ctx.Request().Header().GetHeader(strings.Replace(name, "_", "-", -1)), true
}), }),
"http": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "http": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Request().Header().GetHeader(strings.Replace(name, "_", "-", -1)), true return ctx.Request().Header().GetHeader(strings.Replace(name, "_", "-", -1)), true
}), }),
"host": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "host": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Request().URI().Host(), true return ctx.Request().URI().Host(), true
}), }),
"error": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "error": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
//TODO 暂时忽略 //TODO 暂时忽略
return "", true return "", true
}), }),
"response": Fields{ "response": Fields{
"": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Response().String(), true return ctx.Response().String(), true
}), }),
"body": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "body": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return string(ctx.Response().GetBody()), true return string(ctx.Response().GetBody()), true
}), }),
"header": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "header": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
if name == "" { if name == "" {
return url.Values(ctx.Response().Headers()).Encode(), true return url.Values(ctx.Response().Headers()).Encode(), true
} }
return ctx.Response().GetHeader(strings.Replace(name, "_", "-", -1)), true return ctx.Response().GetHeader(strings.Replace(name, "_", "-", -1)), true
}), }),
"status": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "status": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return ctx.Response().ProxyStatus(), true return ctx.Response().ProxyStatus(), true
}), }),
"time": ReadFunc(func(name string, ctx http_service.IHttpContext) (string, bool) { "time": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
responseTime := ctx.Response().ResponseTime() return ctx.Response().ResponseTime(), true
return strconv.FormatInt(responseTime.Milliseconds(), 10), true }),
"length": ReadFunc(func(name string, ctx http_service.IHttpContext) (interface{}, bool) {
return strconv.Itoa(ctx.Response().ContentLength()), true
}), }),
}, },
"proxy": proxyFields, "proxy": proxyFields,
} }
proxyFields = ProxyReaders{ proxyFields = ProxyReaders{
"header": ProxyReadFunc(func(name string, proxy http_service.IProxy) (string, bool) { "header": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
if name == "" { if name == "" {
return url.Values(proxy.Header().Headers()).Encode(), true return url.Values(proxy.Header().Headers()).Encode(), true
} }
return proxy.Header().GetHeader(strings.Replace(name, "_", "-", -1)), true return proxy.Header().GetHeader(strings.Replace(name, "_", "-", -1)), true
}), }),
"uri": ProxyReadFunc(func(name string, proxy http_service.IProxy) (string, bool) { "uri": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.URI().RequestURI(), true return proxy.URI().RequestURI(), true
}), }),
"query": ProxyReadFunc(func(name string, proxy http_service.IProxy) (string, bool) { "query": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
if name == "" { if name == "" {
return utils.QueryUrlEncode(proxy.URI().RawQuery()), true return utils.QueryUrlEncode(proxy.URI().RawQuery()), true
} }
return url.QueryEscape(proxy.URI().GetQuery(name)), true return url.QueryEscape(proxy.URI().GetQuery(name)), true
}), }),
"body": ProxyReadFunc(func(name string, proxy http_service.IProxy) (string, bool) { "body": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
body, err := proxy.Body().RawBody() body, err := proxy.Body().RawBody()
if err != nil { if err != nil {
return "", false return "", false
} }
return string(body), true return string(body), true
}), }),
"addr": ProxyReadFunc(func(name string, proxy http_service.IProxy) (string, bool) { "addr": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.URI().Host(), true return proxy.URI().Host(), true
}), }),
"scheme": ProxyReadFunc(func(name string, proxy http_service.IProxy) (string, bool) { "scheme": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.URI().Scheme(), true return proxy.URI().Scheme(), true
}), }),
"method": ProxyReadFunc(func(name string, proxy http_service.IProxy) (string, bool) { "method": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.Method(), true return proxy.Method(), true
}), }),
"status": ProxyReadFunc(func(name string, proxy http_service.IProxy) (string, bool) { "status": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.Status(), true return proxy.StatusCode(), true
}), }),
"path": ProxyReadFunc(func(name string, proxy http_service.IProxy) (string, bool) { "path": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.URI().Path(), true return proxy.URI().Path(), true
}), }),
"host": ProxyReadFunc(func(name string, proxy http_service.IProxy) (string, bool) { "host": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.Header().Host(), true return proxy.Header().Host(), true
}), }),
"request_length": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.ContentLength(), true
}),
"response_length": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.ResponseLength(), true
}),
"response_body": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.ResponseBody(), true
}),
"time": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.ResponseTime(), true
}),
"msec": ProxyReadFunc(func(name string, proxy http_service.IProxy) (interface{}, bool) {
return proxy.ProxyTime().UnixMilli(), true
}),
} }
) )

View File

@@ -2,12 +2,13 @@ package metric_entry
import ( import (
"fmt" "fmt"
"strings"
http_entry "github.com/eolinker/apinto/entries/http-entry" http_entry "github.com/eolinker/apinto/entries/http-entry"
"github.com/eolinker/eosc" "github.com/eolinker/eosc"
"github.com/eolinker/eosc/eocontext" "github.com/eolinker/eosc/eocontext"
http_context "github.com/eolinker/eosc/eocontext/http-context" http_context "github.com/eolinker/eosc/eocontext/http-context"
"github.com/eolinker/eosc/log" "github.com/eolinker/eosc/log"
"strings"
) )
type metricEntry struct { type metricEntry struct {
@@ -40,7 +41,7 @@ func (p *metricEntry) GetFloat(pattern string) (float64, bool) {
func (p *metricEntry) Read(pattern string) string { func (p *metricEntry) Read(pattern string) string {
//会先从rule里面读若rule没有相应的pattern会从ctx里面读label //会先从rule里面读若rule没有相应的pattern会从ctx里面读label
value := p.iEntry.Read(pattern) value := eosc.ReadStringFromEntry(p.iEntry, pattern)
if value == "" { if value == "" {
value = "-" value = "-"
} }
@@ -86,7 +87,7 @@ func (p *proxyMetricEntry) Read(pattern string) string {
name := strings.TrimPrefix(pattern, p.prefix) name := strings.TrimPrefix(pattern, p.prefix)
f, exist := p.proxyReaders[name] f, exist := p.proxyReaders[name]
if exist { if exist {
value, has := f.ReadProxy(name, p.proxy) value, has := http_entry.ReadProxyFromProxyReader(f, p.proxy, name)
if !has { if !has {
value = "-" value = "-"
} }

View File

@@ -2,8 +2,7 @@ package monitor_entry
import ( import (
"fmt" "fmt"
"os"
"github.com/eolinker/eosc/utils"
http_context "github.com/eolinker/eosc/eocontext/http-context" http_context "github.com/eolinker/eosc/eocontext/http-context"
"github.com/eolinker/eosc/log" "github.com/eolinker/eosc/log"
@@ -29,10 +28,10 @@ func ReadProxy(ctx http_context.IHttpContext) []IPoint {
return make([]IPoint, 0, 1) return make([]IPoint, 0, 1)
} }
globalLabels := utils.GlobalLabelGet() //globalLabels := utils.GlobalLabelGet()
labelMetrics := map[string]string{ labelMetrics := map[string]string{
"cluster": globalLabels["cluster_id"], "cluster": os.Getenv("cluster_id"),
"node": globalLabels["node_id"], "node": os.Getenv("node_id"),
} }
for key, label := range labels { for key, label := range labels {
value := ctx.GetLabel(label) value := ctx.GetLabel(label)

View File

@@ -1,10 +1,9 @@
package monitor_entry package monitor_entry
import ( import (
"os"
"time" "time"
"github.com/eolinker/eosc/utils"
"github.com/eolinker/eosc/log" "github.com/eolinker/eosc/log"
http_context "github.com/eolinker/eosc/eocontext/http-context" http_context "github.com/eolinker/eosc/eocontext/http-context"
@@ -26,10 +25,9 @@ var requestFields = []string{
type RequestReadFunc func(ctx http_context.IHttpContext) (interface{}, bool) type RequestReadFunc func(ctx http_context.IHttpContext) (interface{}, bool)
func ReadRequest(ctx http_context.IHttpContext) []IPoint { func ReadRequest(ctx http_context.IHttpContext) []IPoint {
globalLabels := utils.GlobalLabelGet()
tags := map[string]string{ tags := map[string]string{
"cluster": globalLabels["cluster_id"], "cluster": os.Getenv("cluster_id"),
"node": globalLabels["node_id"], "node": os.Getenv("node_id"),
} }
for key, label := range labels { for key, label := range labels {

3
go.mod
View File

@@ -5,9 +5,10 @@ go 1.19
require ( require (
github.com/Shopify/sarama v1.32.0 github.com/Shopify/sarama v1.32.0
github.com/brianvoe/gofakeit/v6 v6.20.1 github.com/brianvoe/gofakeit/v6 v6.20.1
github.com/clbanning/mxj v1.8.4
github.com/coocood/freecache v1.2.2 github.com/coocood/freecache v1.2.2
github.com/dubbogo/gost v1.13.1 github.com/dubbogo/gost v1.13.1
github.com/eolinker/eosc v0.14.2 github.com/eolinker/eosc v0.14.3
github.com/fasthttp/websocket v1.5.0 github.com/fasthttp/websocket v1.5.0
github.com/fullstorydev/grpcurl v1.8.7 github.com/fullstorydev/grpcurl v1.8.7
github.com/go-redis/redis/v8 v8.11.5 github.com/go-redis/redis/v8 v8.11.5

View File

@@ -1,14 +1,15 @@
package monitor_manager package monitor_manager
import ( import (
"os"
"reflect"
"time"
"github.com/eolinker/apinto/entries/monitor-entry" "github.com/eolinker/apinto/entries/monitor-entry"
"github.com/eolinker/apinto/scope-manager" "github.com/eolinker/apinto/scope-manager"
"github.com/eolinker/eosc" "github.com/eolinker/eosc"
"github.com/eolinker/eosc/common/bean" "github.com/eolinker/eosc/common/bean"
"github.com/eolinker/eosc/log" "github.com/eolinker/eosc/log"
"github.com/eolinker/eosc/utils"
"reflect"
"time"
) )
var _ IManager = (*MonitorManager)(nil) var _ IManager = (*MonitorManager)(nil)
@@ -36,11 +37,10 @@ func (o *MonitorManager) RemoveCurrencyAPI(apiID string) {
v, ok := o.concurrentApis.Del(apiID) v, ok := o.concurrentApis.Del(apiID)
if ok { if ok {
now := time.Now() now := time.Now()
globalLabel := utils.GlobalLabelGet()
tags := map[string]string{ tags := map[string]string{
"api": apiID, "api": apiID,
"cluster": globalLabel["cluster"], "cluster": os.Getenv("cluster_id"),
"node": globalLabel["node"], "node": os.Getenv("node_id"),
} }
fields := map[string]interface{}{ fields := map[string]interface{}{
"value": v.Get(), "value": v.Get(),
@@ -120,9 +120,8 @@ func (o *MonitorManager) proxyOutput(v scope_manager.IProxyOutput[monitor_entry.
func (o *MonitorManager) genNodePoints() []monitor_entry.IPoint { func (o *MonitorManager) genNodePoints() []monitor_entry.IPoint {
now := time.Now() now := time.Now()
globalLabel := utils.GlobalLabelGet() cluster := os.Getenv("cluster_id")
cluster := globalLabel["cluster"] node := os.Getenv("node_id")
node := globalLabel["node"]
points := make([]monitor_entry.IPoint, 0, o.concurrentApis.Count()) points := make([]monitor_entry.IPoint, 0, o.concurrentApis.Count())
for key, value := range o.concurrentApis.All() { for key, value := range o.concurrentApis.All() {
tags := map[string]string{ tags := map[string]string{

View File

@@ -2,13 +2,14 @@ package fasthttp_client
import ( import (
"fmt" "fmt"
"github.com/eolinker/eosc/eocontext"
"net" "net"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/eolinker/eosc/eocontext"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
) )

View File

@@ -6,6 +6,10 @@ import (
"net" "net"
"time" "time"
http_entry "github.com/eolinker/apinto/entries/http-entry"
"github.com/eolinker/eosc"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
"github.com/eolinker/eosc/utils/config" "github.com/eolinker/eosc/utils/config"
@@ -31,8 +35,15 @@ type cloneContext struct {
balance eoscContext.BalanceHandler balance eoscContext.BalanceHandler
upstreamHostHandler eoscContext.UpstreamHostHandler upstreamHostHandler eoscContext.UpstreamHostHandler
labels map[string]string labels map[string]string
entry eosc.IEntry
responseError error
}
responseError error func (ctx *cloneContext) GetEntry() eosc.IEntry {
if ctx.entry == nil {
ctx.entry = http_entry.NewEntry(ctx)
}
return ctx.entry
} }
func (ctx *cloneContext) RealIP() string { func (ctx *cloneContext) RealIP() string {
@@ -137,6 +148,7 @@ func (ctx *cloneContext) SendTo(scheme string, node eoscContext.INode, timeout t
} else { } else {
agent.setStatusCode(ctx.response.Response.StatusCode()) agent.setStatusCode(ctx.response.Response.StatusCode())
} }
agent.responseBody = string(ctx.response.Response.Body())
agent.setResponseLength(ctx.response.Response.Header.ContentLength()) agent.setResponseLength(ctx.response.Response.Header.ContentLength())

View File

@@ -6,6 +6,10 @@ import (
"net" "net"
"time" "time"
http_entry "github.com/eolinker/apinto/entries/http-entry"
"github.com/eolinker/eosc"
"github.com/eolinker/apinto/entries/ctx_key" "github.com/eolinker/apinto/entries/ctx_key"
"github.com/eolinker/eosc/utils/config" "github.com/eolinker/eosc/utils/config"
@@ -36,6 +40,7 @@ type HttpContext struct {
upstreamHostHandler eoscContext.UpstreamHostHandler upstreamHostHandler eoscContext.UpstreamHostHandler
labels map[string]string labels map[string]string
port int port int
entry eosc.IEntry
} }
func (ctx *HttpContext) RealIP() string { func (ctx *HttpContext) RealIP() string {
@@ -70,6 +75,13 @@ func (ctx *HttpContext) SetBalance(handler eoscContext.BalanceHandler) {
ctx.balance = handler ctx.balance = handler
} }
func (ctx *HttpContext) GetEntry() eosc.IEntry {
if ctx.entry == nil {
ctx.entry = http_entry.NewEntry(ctx)
}
return ctx.entry
}
func (ctx *HttpContext) SetLabel(name, value string) { func (ctx *HttpContext) SetLabel(name, value string) {
ctx.labels[name] = value ctx.labels[name] = value
} }
@@ -141,7 +153,7 @@ func (ctx *HttpContext) SendTo(scheme string, node eoscContext.INode, timeout ti
ctx.response.ResponseHeader.refresh() ctx.response.ResponseHeader.refresh()
agent.setStatusCode(ctx.fastHttpRequestCtx.Response.StatusCode()) agent.setStatusCode(ctx.fastHttpRequestCtx.Response.StatusCode())
} }
agent.responseBody = string(ctx.response.Response.Body())
agent.setResponseLength(ctx.fastHttpRequestCtx.Response.Header.ContentLength()) agent.setResponseLength(ctx.fastHttpRequestCtx.Response.Header.ContentLength())
ctx.proxyRequests = append(ctx.proxyRequests, agent) ctx.proxyRequests = append(ctx.proxyRequests, agent)

View File

@@ -16,11 +16,16 @@ type requestAgent struct {
statusCode int statusCode int
status string status string
responseLength int responseLength int
responseBody string
beginTime time.Time beginTime time.Time
endTime time.Time endTime time.Time
hostAgent *UrlAgent hostAgent *UrlAgent
} }
func (a *requestAgent) ResponseBody() string {
return a.responseBody
}
func (a *requestAgent) ProxyTime() time.Time { func (a *requestAgent) ProxyTime() time.Time {
return a.beginTime return a.beginTime
} }

View File

@@ -3,11 +3,13 @@ package http_context
import ( import (
"errors" "errors"
"fmt" "fmt"
eoscContext "github.com/eolinker/eosc/eocontext"
"io" "io"
"net" "net"
"sync" "sync"
eoscContext "github.com/eolinker/eosc/eocontext"
"github.com/valyala/fasthttp"
"github.com/eolinker/eosc/log" "github.com/eolinker/eosc/log"
"github.com/eolinker/eosc/utils/config" "github.com/eolinker/eosc/utils/config"
@@ -24,7 +26,9 @@ type WebsocketContext struct {
upstreamConn net.Conn upstreamConn net.Conn
} }
var upgrader = websocket.FastHTTPUpgrader{} var upgrader = websocket.FastHTTPUpgrader{
CheckOrigin: func(ctx *fasthttp.RequestCtx) bool { return true },
}
func (w *WebsocketContext) Upgrade() error { func (w *WebsocketContext) Upgrade() error {
err := upgrader.Upgrade(w.fastHttpRequestCtx, func(conn *websocket.Conn) { err := upgrader.Upgrade(w.fastHttpRequestCtx, func(conn *websocket.Conn) {