package plugin import ( "encoding/base64" "reflect" "regexp" "strings" "apigo.cc/gojs" "apigo.cc/gojs/goja" "github.com/ssgo/config" "github.com/ssgo/u" ) const pluginName = "api" var confAes *u.Aes = u.NewAes([]byte("?GQ$0K0GgLdO=f+~L68PLm$uhKr4'=tV"), []byte("VFs7@sK61cj^f?HZ")) type Result struct { StatusCode int Status string Headers map[string]string Data any } func init() { config.LoadConfig(pluginName, &signerConfig) Config(signerConfig) obj := map[string]any{ "config": Config, "registerSigner": RegisterSigner, "sortParams": SortParams, } for signer := range signerConfig { cfg := signerConfig[signer] o := map[string]any{} o["do"] = MakeAction(signer, nil) o["get"] = MakeAction(signer, map[string]any{ "method": "GET", }) o["post"] = MakeAction(signer, map[string]any{ "method": "POST", }) o["put"] = MakeAction(signer, map[string]any{ "method": "PUT", }) o["delete"] = MakeAction(signer, map[string]any{ "method": "DELETE", }) o["head"] = MakeAction(signer, map[string]any{ "method": "HEAD", }) o["options"] = MakeAction(signer, map[string]any{ "method": "OPTIONS", }) actions := map[string]map[string]any{} u.Convert((*cfg)["actions"], &actions) for k, v := range actions { o[k] = MakeAction(signer, v) } obj[signer] = o } tsCode := gojs.MakeTSCode(obj) mappedObj := gojs.ToMap(obj) gojs.Register("apigo.cc/gojs/"+pluginName, gojs.Module{ ObjectMaker: func(vm *goja.Runtime) gojs.Map { return mappedObj }, TsCode: tsCode, Desc: pluginName, }) } func MakeAction(signer string, actionCfg map[string]any) func(req *Request) (*Result, error) { cfg := &SignerConfig{data: map[string]any{}} if c := signerConfig[signer]; c != nil { u.Convert(c, cfg.data) delete(cfg.data, "actions") } defaultUrl := cfg.String("url", "") reqSet := &Request{} u.Convert(actionCfg, reqSet) delete(actionCfg, "headers") delete(actionCfg, "query") delete(actionCfg, "data") delete(actionCfg, "form") delete(actionCfg, "file") delete(actionCfg, "text") delete(actionCfg, "binary") delete(actionCfg, "requestType") delete(actionCfg, "callback") delete(actionCfg, "timeout") u.Convert(actionCfg, cfg.data) makeConfigVar(cfg.data, reflect.ValueOf(cfg.data)) // 没有在外层配置url,或者url中有待处理的变量 if defaultUrl == "" || strings.Contains(defaultUrl, "{{.") { defaultUrl = cfg.String("url", "") } return func(req *Request) (*Result, error) { if req == nil { req = &Request{} } var req1 *Request if reqSet != nil { req1v := *reqSet req1 = &req1v if req.Url != "" { req1.Url = req.Url } if req.Method != "" { req1.Method = req.Method } if req.Config != nil { if req1.Config == nil { req1.Config = map[string]string{} } for k, v := range req.Config { req1.Config[k] = v } } if req.Headers != nil { if req1.Headers == nil { req1.Headers = map[string]string{} } for k, v := range req.Headers { req1.Headers[k] = v } } if req.Query != nil { if req1.Query == nil { req1.Query = map[string]string{} } for k, v := range req.Query { req1.Query[k] = v } } if req.Data != nil { if req1.Data == nil { req1.Data = map[string]any{} } for k, v := range req.Data { req1.Data[k] = v } } if req.Form != nil { if req1.Form == nil { req1.Form = map[string]string{} } for k, v := range req.Form { req1.Form[k] = v } } if req.File != nil { if req1.File == nil { req1.File = map[string]any{} } for k, v := range req.File { req1.File[k] = v } } if req.Text != "" { req1.Text = req.Text } if req.Binary != nil { req1.Binary = req.Binary } if req.RequestType != "" { req1.RequestType = req.RequestType } if req.ResponseType != "" { req1.ResponseType = req.ResponseType } if req.Callback != nil { req1.Callback = req.Callback } if req.Timeout == 0 { req1.Timeout = req.Timeout } } else { req1 = req } if !strings.Contains(req1.Url, "://") && defaultUrl != "" { has1 := strings.HasSuffix(defaultUrl, "/") has2 := strings.HasPrefix(req1.Url, "/") if !has1 && !has2 { req1.Url = defaultUrl + "/" + req1.Url } else if has1 && has2 { req1.Url = defaultUrl + req1.Url[1:] } else { req1.Url = defaultUrl + req1.Url } } data, resp, err := Do(cfg, req1) headers := map[string]string{} statusCode := 0 status := "" if resp != nil { statusCode = resp.StatusCode status = resp.Status for k, v := range resp.Header { headers[k] = v[0] } } return &Result{ Status: status, StatusCode: statusCode, Headers: headers, Data: data, }, err } } func Config(cfg map[string]*map[string]any) { for k, v := range cfg { if u.String((*v)["signer"]) == "" { (*v)["signer"] = k } // 尝试解密配置 decryptConfig(reflect.ValueOf(v)) makeConfigVar((*v), reflect.ValueOf(v)) confLock.Lock() signerConfig[k] = v confLock.Unlock() } } func decryptConfig(v reflect.Value) { v = u.FinalValue(v) if v.Kind() == reflect.Map { for _, k := range v.MapKeys() { v2 := u.FinalValue(v.MapIndex(k)) if v2.Kind() == reflect.String { if b64, err := base64.URLEncoding.DecodeString(v2.String()); err == nil { if dec, err := confAes.DecryptBytes(b64); err == nil { v.SetMapIndex(k, reflect.ValueOf(string(dec))) } } } else if v2.Kind() == reflect.Map || v.Kind() == reflect.Slice { decryptConfig(v2) } } } else if v.Kind() == reflect.Slice { for i := 0; i < v.Len(); i++ { v2 := u.FinalValue(v.Index(i)) if v2.Kind() == reflect.String { if b64, err := base64.URLEncoding.DecodeString(v2.String()); err == nil { if dec, err := confAes.DecryptBytes(b64); err == nil { v.Index(i).Set(reflect.ValueOf(string(dec))) } } } else if v2.Kind() == reflect.Map || v.Kind() == reflect.Slice { decryptConfig(v2) } } } } var varMatcher = regexp.MustCompile(`{{\.([\w\.\-]+)}}`) var configMatcher = regexp.MustCompile(`{{config\.([\w\.\-]+)}}`) var fnMatcher = regexp.MustCompile(`{{/(\w+)\s*(.*?)}}`) func makeConfigVar(cfg map[string]any, v reflect.Value) { v = u.FinalValue(v) if v.Kind() == reflect.Map { for _, k := range v.MapKeys() { v2 := u.FinalValue(v.MapIndex(k)) if v2.Kind() == reflect.String { str := v2.String() if m := varMatcher.FindAllStringSubmatch(str, 100); m != nil { for _, m1 := range m { if v1 := getConfigValue(cfg, m1[1]); v1 != "" { str = strings.ReplaceAll(str, m1[0], v1) } } v.SetMapIndex(k, reflect.ValueOf(str)) } } else if v2.Kind() == reflect.Map || v.Kind() == reflect.Slice { makeConfigVar(cfg, v2) } } } else if v.Kind() == reflect.Slice { for i := 0; i < v.Len(); i++ { v2 := u.FinalValue(v.Index(i)) if v2.Kind() == reflect.String { str := v2.String() if m := varMatcher.FindAllStringSubmatch(str, 100); m != nil { for _, m1 := range m { if v1 := getConfigValue(cfg, m1[1]); v1 != "" { str = strings.ReplaceAll(str, m1[0], v1) } } v.Index(i).Set(reflect.ValueOf(str)) } } else if v2.Kind() == reflect.Map || v.Kind() == reflect.Slice { makeConfigVar(cfg, v2) } } } }