许多修改

This commit is contained in:
Star 2025-12-01 00:30:00 +08:00
parent 30a821c217
commit 275512e492
6 changed files with 397 additions and 195 deletions

197
API.go
View File

@ -16,12 +16,22 @@ import (
"sync" "sync"
"time" "time"
"apigo.cc/gojs"
"apigo.cc/gojs/goja"
xml2json "github.com/basgys/goxml2json" xml2json "github.com/basgys/goxml2json"
"github.com/ssgo/httpclient" "github.com/ssgo/httpclient"
"github.com/ssgo/u" "github.com/ssgo/u"
) )
var Signers = map[string]func(req *Request, cfg *SignerConfig) error{ type SignerCode struct {
Code string
Version uint64
}
var jsSigners = map[string]*SignerCode{}
var actionConfigs = map[string]*ApiConfig{}
var goSigners = map[string]func(req *Request, cfg *ApiConfig) error{
// 基础认证 // 基础认证
"basic": makeBasicAuthSign, "basic": makeBasicAuthSign,
"bearer": makeBearerSign, "bearer": makeBearerSign,
@ -30,79 +40,134 @@ var Signers = map[string]func(req *Request, cfg *SignerConfig) error{
// "cos": makeCOSSign, // "cos": makeCOSSign,
// "hmac": makeHmacSign, // "hmac": makeHmacSign,
} }
var signersLock = sync.RWMutex{} var actionsLock = sync.RWMutex{}
func GetSigner(name string) func(req *Request, cfg *SignerConfig) error { type ApiConfig struct {
if name == "" {
return nil
}
signersLock.RLock()
defer signersLock.RUnlock()
return Signers[name]
}
func RegisterSigner(name string, f func(req *Request, cfg *SignerConfig) error) {
signersLock.Lock()
defer signersLock.Unlock()
Signers[name] = f
}
type SignerConfig struct {
data map[string]any data map[string]any
} }
var signerConfig = map[string]*map[string]any{} var apiConfigs = map[string]*map[string]any{}
var confLock = sync.RWMutex{} var confLock = sync.RWMutex{}
func GetSignerConfig(signer string) *SignerConfig { func GetSigner(name string, vm *goja.Runtime) func(req *Request, cfg *ApiConfig) error {
if name == "" {
return nil
}
var jsi *SignerCode
actionsLock.RLock()
si := goSigners[name]
if si == nil {
jsi = jsSigners[name]
}
actionsLock.RUnlock()
// 获取当前VM的Signer
if jsi != nil {
if jsi.Version != u.Uint64(vm.GetData("__api_signer_version_"+name)) {
// 从代码更新
vm.SetData("__api_signer_version_"+name, jsi.Version)
if fnV, err := vm.RunString("(" + jsi.Code + ")"); err == nil {
if fn, ok := goja.AssertFunction(fnV); ok {
si = func(req *Request, cfg *ApiConfig) error {
_, err := fn(nil, vm.ToValue(gojs.ToMap(req)), vm.ToValue(gojs.ToMap(cfg)))
return err
}
vm.SetData("__signer_"+name, si)
}
}
} else {
// 从vm中直接获取
if si1, ok := vm.GetData("__signer_" + name).(func(req *Request, cfg *ApiConfig) error); ok {
si = si1
}
}
}
return si
}
func GetSignerVersion(name string) uint64 {
actionsLock.Lock()
defer actionsLock.Unlock()
si := jsSigners[name]
if si == nil {
return 0
}
return si.Version
}
// func RegisterSigner(name string, f func(req *Request, cfg *SignerConfig) error) {
func RegisterSigner(name string, fnCode string, fnVersion *uint64, vm *goja.Runtime) error {
version := u.Uint64(fnVersion)
if version == 0 {
version = 1
}
// fmt.Println(name, fnCode, version)
if fnV, err := vm.RunString("(" + fnCode + ")"); err == nil {
if _, ok := goja.AssertFunction(fnV); !ok {
return gojs.Err("signer must be a function")
}
} else {
return gojs.Err(err)
}
actionsLock.Lock()
defer actionsLock.Unlock()
jsSigners[name] = &SignerCode{
Code: fnCode,
Version: version,
}
return nil
}
func GetSignerConfig(signer string) *ApiConfig {
confLock.RLock() confLock.RLock()
cfg := signerConfig[signer] cfg := apiConfigs[signer]
confLock.RUnlock() confLock.RUnlock()
if cfg == nil { if cfg == nil {
cfg = &map[string]any{} cfg = &map[string]any{}
} }
return &SignerConfig{data: *cfg} return &ApiConfig{data: *cfg}
} }
// func (cfg *SignerConfig) Signer() string { // func (cfg *SignerConfig) Signer() string {
// return u.String(cfg.data["signer"]) // return u.String(cfg.data["signer"])
// } // }
func (cfg *SignerConfig) Get(k string, defaultValue any) any { func (cfg *ApiConfig) Get(k string, defaultValue any) any {
if v, ok := cfg.data[k]; ok { if v, ok := cfg.data[k]; ok {
return v return v
} }
return defaultValue return defaultValue
} }
func (cfg *SignerConfig) Set(k string, v any) { func (cfg *ApiConfig) Set(k string, v any) {
cfg.data[k] = v cfg.data[k] = v
} }
func (cfg *SignerConfig) String(k string, defaultValue string) string { func (cfg *ApiConfig) String(k string, defaultValue string) string {
return u.String(cfg.Get(k, defaultValue)) return u.String(cfg.Get(k, defaultValue))
} }
func (cfg *SignerConfig) Int(k string, defaultValue int64) int64 { func (cfg *ApiConfig) Int(k string, defaultValue int64) int64 {
return u.Int64(cfg.Get(k, defaultValue)) return u.Int64(cfg.Get(k, defaultValue))
} }
func (cfg *SignerConfig) Float(k string, defaultValue float64) float64 { func (cfg *ApiConfig) Float(k string, defaultValue float64) float64 {
return u.Float64(cfg.Get(k, defaultValue)) return u.Float64(cfg.Get(k, defaultValue))
} }
func (cfg *SignerConfig) Bool(k string, defaultValue bool) bool { func (cfg *ApiConfig) Bool(k string, defaultValue bool) bool {
return u.Bool(cfg.Get(k, defaultValue)) return u.Bool(cfg.Get(k, defaultValue))
} }
func (cfg *SignerConfig) To(k string, to any) { func (cfg *ApiConfig) To(k string, to any) {
from := cfg.Get(k, nil) from := cfg.Get(k, nil)
if from != nil { if from != nil {
u.Convert(from, to) u.Convert(from, to)
} }
} }
func (cfg *SignerConfig) Map(k string) map[string]any { func (cfg *ApiConfig) Map(k string) map[string]any {
m := map[string]any{} m := map[string]any{}
cfg.To(k, &m) cfg.To(k, &m)
return m return m
@ -374,7 +439,7 @@ func (req *Request) MakeBody() {
} }
} }
func MakeSign(cfg *SignerConfig, req *Request) error { func MakeSign(cfg *ApiConfig, req *Request, vm *goja.Runtime) error {
if req.RequestType == "" { if req.RequestType == "" {
if req.Data != nil { if req.Data != nil {
req.RequestType = RequestType.Json req.RequestType = RequestType.Json
@ -426,7 +491,7 @@ func MakeSign(cfg *SignerConfig, req *Request) error {
} }
if cfg == nil { if cfg == nil {
cfg = &SignerConfig{} cfg = &ApiConfig{}
} }
// 从signer中设置header // 从signer中设置header
@ -453,7 +518,7 @@ func MakeSign(cfg *SignerConfig, req *Request) error {
req.MakeQuery() req.MakeQuery()
req.MakeBody() req.MakeBody()
if signer := GetSigner(u.String(cfg.data["signer"])); signer != nil { if signer := GetSigner(u.String(cfg.data["signer"]), vm); signer != nil {
// fmt.Println(111, req.Method, 111) // fmt.Println(111, req.Method, 111)
if err := signer(req, cfg); err != nil { if err := signer(req, cfg); err != nil {
// fmt.Println(333, err) // fmt.Println(333, err)
@ -466,38 +531,52 @@ func MakeSign(cfg *SignerConfig, req *Request) error {
return nil return nil
} }
func Get(cfg *SignerConfig, req *Request) (any, *http.Response, error) { // func Get(cfg *SignerConfig, req *Request, vm *goja.Runtime) (any, *http.Response, error) {
req.Method = "GET" // req.Method = "GET"
return Do(cfg, req) // return Do(cfg, req, vm)
} // }
func Post(cfg *SignerConfig, req *Request) (any, *http.Response, error) { // func Post(cfg *SignerConfig, req *Request, vm *goja.Runtime) (any, *http.Response, error) {
req.Method = "POST" // req.Method = "POST"
return Do(cfg, req) // return Do(cfg, req, vm)
} // }
func Put(cfg *SignerConfig, req *Request) (any, *http.Response, error) { // func Put(cfg *SignerConfig, req *Request, vm *goja.Runtime) (any, *http.Response, error) {
req.Method = "PUT" // req.Method = "PUT"
return Do(cfg, req) // return Do(cfg, req, vm)
} // }
func Delete(cfg *SignerConfig, req *Request) (any, *http.Response, error) { // func Delete(cfg *SignerConfig, req *Request, vm *goja.Runtime) (any, *http.Response, error) {
req.Method = "DELETE" // req.Method = "DELETE"
return Do(cfg, req) // return Do(cfg, req, vm)
} // }
func Head(cfg *SignerConfig, req *Request) (any, *http.Response, error) { // func Head(cfg *SignerConfig, req *Request, vm *goja.Runtime) (any, *http.Response, error) {
req.Method = "HEAD" // req.Method = "HEAD"
return Do(cfg, req) // return Do(cfg, req, vm)
} // }
func Options(cfg *SignerConfig, req *Request) (any, *http.Response, error) { // func Options(cfg *SignerConfig, req *Request, vm *goja.Runtime) (any, *http.Response, error) {
req.Method = "OPTIONS" // req.Method = "OPTIONS"
return Do(cfg, req) // return Do(cfg, req, vm)
} // }
func Do(cfg *SignerConfig, req *Request) (any, *http.Response, error) { func Do(action string, req *Request, vm *goja.Runtime) (any, *http.Response, error) {
err := MakeSign(cfg, req) var cfg *ApiConfig
if action != "" {
action1 := u.SplitTrimN(action, ".", 2)[0]
actionsLock.RLock()
cfg = actionConfigs[action]
if cfg == nil {
cfg = actionConfigs[action1]
}
actionsLock.RUnlock()
}
if cfg == nil {
cfg = &ApiConfig{data: map[string]any{}}
}
err := MakeSign(cfg, req, vm)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@ -1,9 +1,11 @@
import co from 'apigo.cc/gojs/console' import co from 'apigo.cc/gojs/console'
import u from 'apigo.cc/gojs/util' import u from 'apigo.cc/gojs/util'
import api from 'apigo.cc/gojs/api' import api from 'apigo.cc/gojs/api'
import file from 'apigo.cc/gojs/file'
// 注册腾讯云TC3签名器 // 注册腾讯云TC3签名器
api.registerSigner("tc3", (req, cfg) => { api.registerSigner("tc3", ((req, cfg) => {
import u from 'apigo.cc/gojs/util'
let action = cfg.string("action", "") let action = cfg.string("action", "")
let service = cfg.string("service", "") let service = cfg.string("service", "")
let timestamp = u.timestamp() let timestamp = u.timestamp()
@ -26,10 +28,11 @@ api.registerSigner("tc3", (req, cfg) => {
req.setHeader("X-TC-Version", cfg.string("version", "")) req.setHeader("X-TC-Version", cfg.string("version", ""))
req.setHeader("X-TC-Region", cfg.string("region", "")) req.setHeader("X-TC-Region", cfg.string("region", ""))
req.setHeader("Authorization", authorization) req.setHeader("Authorization", authorization)
}) }).toString())
// 腾讯云COS签名 // 腾讯云COS签名
api.registerSigner("cos", (req, cfg) => { api.registerSigner("cos", ((req, cfg) => {
import u from 'apigo.cc/gojs/util'
let startTimestamp = u.timestamp() let startTimestamp = u.timestamp()
let keyTime = startTimestamp + ";" + startTimestamp + cfg.int("expiredTime", 600) let keyTime = startTimestamp + ";" + startTimestamp + cfg.int("expiredTime", 600)
let signKey = u.hex(u.hmacSHA1(cfg.string("secretKey", ""), keyTime)) let signKey = u.hex(u.hmacSHA1(cfg.string("secretKey", ""), keyTime))
@ -39,25 +42,25 @@ api.registerSigner("cos", (req, cfg) => {
let signature = u.hex(u.hmacSHA1(signKey, "sha1\n" + keyTime + "\n" + hashedHttpString + "\n")) let signature = u.hex(u.hmacSHA1(signKey, "sha1\n" + keyTime + "\n" + hashedHttpString + "\n"))
let authorization = "q-sign-algorithm=sha1&q-ak=" + cfg.string("secretId", "") + "&q-sign-time=" + keyTime + "&q-key-time=" + keyTime + "&q-header-list=" + headerList + "&q-url-param-list=" + urlParamList + "&q-signature=" + signature let authorization = "q-sign-algorithm=sha1&q-ak=" + cfg.string("secretId", "") + "&q-sign-time=" + keyTime + "&q-key-time=" + keyTime + "&q-header-list=" + headerList + "&q-url-param-list=" + urlParamList + "&q-signature=" + signature
req.setHeader("Authorization", authorization) req.setHeader("Authorization", authorization)
}) }).toString())
try { try {
// let r = api.tencent.smsPackagesStatistics({ data: { SmsSdkAppId: '1400624676', BeginTime: '2025010100', EndTime: '2045010100' } }) // let r = api.tencent.smsPackagesStatistics({ data: { SmsSdkAppId: '1400624676', BeginTime: '2025010100', EndTime: '2045010100' } })
// let r = api.tencent.getBucketList() let r = api.tencent.getBucketList()
// let r = api.laoCos.get({ url: "/?max-keys=5" }) // let r = api.laoCos.get({ url: "/?max-keys=5" })
// let r = api.laoCos.get({ url: "user/9VKQpY2RH7Ks/avatar.jpg", responseType: 'text/plain' }) // let r = api.laoCos.get({ url: "user/9VKQpY2RH7Ks/avatar.jpg", responseType: 'text/plain' })
// let r = api.laoCos.put({ url: "test/aaa.txt", text: 'hello world' }) // let r = api.laoCos.put({ url: "test/aaa.txt", text: 'hello world' })
// let r = api.laoCos.get({ url: "test/aaa.txt" }) // let r = api.laoCos.get({ url: "test/aaa.txt" })
// let r = api.tencent.getCosToken({ config: { path: '/aaa/111' } }) // let r = api.tencent.getCosToken({ config: { path: '/aaa/111' } })
// co.info(r) co.info(r)
// 测试llm接口 // 测试llm接口
// let r = api.zhipujwt.do({ url: "https://open.bigmodel.cn/api/paas/v4/chat/completions", data: { model: 'GLM-4.5-Flash', messages: [{ role: 'user', content: '你好' }], thinking: { type: 'disabled' } } }) // let r = api.zhipujwt.do({ url: "https://open.bigmodel.cn/api/paas/v4/chat/completions", data: { model: 'GLM-4.5-Flash', messages: [{ role: 'user', content: '你好' }], thinking: { type: 'disabled' } } })
// test('智谱(jwt):简单对话(.do)', r.statusCode == 200 && !!r.data, r?.data?.choices[0]?.message?.content, r) // test('智谱(jwt):简单对话(.do)', r.statusCode == 200 && !!r.data, r?.data?.choices[0]?.message?.content, r)
// testChat('PPIO(openai)', api.openai) testChat('PPIO(openai)', api.openai)
// testChat('智谱', api.zhipu) // testChat('智谱', api.zhipu)
testChat('豆包', api.doubao) // testChat('豆包', api.doubao)
// let r = api.zhipu.image({ data: { prompt: '一张猫在沙发上喝咖啡' } }) // let r = api.zhipu.image({ data: { prompt: '一张猫在沙发上喝咖啡' } })
// test('智谱:图片生成', r.statusCode == 200 && !!r.data, r?.data?.data[0]?.url, r) // test('智谱:图片生成', r.statusCode == 200 && !!r.data, r?.data?.data[0]?.url, r)
@ -72,6 +75,35 @@ try {
// let r = api.textin.scan({ binary: fs.readBytes('testRes/table.jpeg') }) // let r = api.textin.scan({ binary: fs.readBytes('testRes/table.jpeg') })
// test('Textin表格识别', r.statusCode == 200 && !!r.data, r?.data, r) // test('Textin表格识别', r.statusCode == 200 && !!r.data, r?.data, r)
// 测试动态配置
let zhipuKey = file.read('env.yml').match(/zhipu:.*?key: (.*?)\n/s)[1]
let zp = {
url: 'https://open.bigmodel.cn/api/paas/v4',
key: zhipuKey,
headers: {
'Authorization': 'Bearer {{.key}}',
},
actions: {
chat: {
url: '/chat/completions',
data: {
model: 'GLM-4.5-Flash',
thinking: {
type: 'disabled',
},
},
},
},
}
api.config('zp', zp)
let r1 = api.zp.chat({ callback: v => { co.println(co.yellow(v.choices[0].delta.content) + ' ') }, data: { messages: [{ role: 'user', content: '1+1=多少?说人话简单点' }], stream: true } })
test('动态配置v1', r1.statusCode == 200 && !!r1.data, r1?.data?.choices[0]?.message?.content, r1)
zp.actions.chat.data.thinking.type = 'enabled'
api.config('zp', zp, 2)
r1 = api.zp.chat({ callback: v => { co.println(co.yellow(v.choices[0]?.delta?.reasoning_content || v.choices[0]?.delta?.content) + ' ') }, data: { messages: [{ role: 'user', content: '1+2=多少?说人话简单点' }], stream: true } })
test('动态配置v2', r1.statusCode == 200 && !!r1.data, r1?.data?.choices[0]?.message, r1)
return true return true
} catch (ex) { } catch (ex) {
return ex.message return ex.message

View File

@ -14,7 +14,7 @@ import (
) )
// 基本认证签名器 // 基本认证签名器
func makeBasicAuthSign(req *Request, cfg *SignerConfig) error { func makeBasicAuthSign(req *Request, cfg *ApiConfig) error {
// 1. 获取用户名和密码 // 1. 获取用户名和密码
username := cfg.String("username", "") username := cfg.String("username", "")
password := cfg.String("password", "") password := cfg.String("password", "")
@ -30,13 +30,13 @@ func makeBasicAuthSign(req *Request, cfg *SignerConfig) error {
} }
// Bearer Token认证 // Bearer Token认证
func makeBearerSign(req *Request, cfg *SignerConfig) error { func makeBearerSign(req *Request, cfg *ApiConfig) error {
req.Headers["Authorization"] = "Bearer " + cfg.String("key", "") req.Headers["Authorization"] = "Bearer " + cfg.String("key", "")
return nil return nil
} }
// 通用JWT签名器 // 通用JWT签名器
func makeJWTSign(req *Request, cfg *SignerConfig) error { func makeJWTSign(req *Request, cfg *ApiConfig) error {
// 1. 获取JWT配置 // 1. 获取JWT配置
secret := cfg.String("secret", "") secret := cfg.String("secret", "")
algorithm := cfg.String("algorithm", "HS256") algorithm := cfg.String("algorithm", "HS256")

21
go.mod
View File

@ -3,11 +3,11 @@ module apigo.cc/gojs/api
go 1.24.0 go 1.24.0
require ( require (
apigo.cc/gojs v0.0.26 apigo.cc/gojs v0.0.30
apigo.cc/gojs/console v0.0.2 apigo.cc/gojs/console v0.0.4
apigo.cc/gojs/file v0.0.5 apigo.cc/gojs/file v0.0.7
apigo.cc/gojs/runtime v0.0.3 apigo.cc/gojs/runtime v0.0.4
apigo.cc/gojs/util v0.0.14 apigo.cc/gojs/util v0.0.16
github.com/basgys/goxml2json v1.1.0 github.com/basgys/goxml2json v1.1.0
github.com/ssgo/config v1.7.10 github.com/ssgo/config v1.7.10
github.com/ssgo/httpclient v1.7.8 github.com/ssgo/httpclient v1.7.8
@ -22,19 +22,18 @@ require (
require ( require (
github.com/ZZMarquis/gm v1.3.2 // indirect github.com/ZZMarquis/gm v1.3.2 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/emmansun/gmsm v0.32.0 // indirect github.com/emmansun/gmsm v0.40.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 github.com/golang-jwt/jwt/v5 v5.3.0
github.com/google/pprof v0.0.0-20250903194437-c28834ac2320 // indirect github.com/google/pprof v0.0.0-20250903194437-c28834ac2320 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/obscuren/ecies v0.0.0-20150213224233-7c0f4a9b18d9 // indirect github.com/obscuren/ecies v0.0.0-20150213224233-7c0f4a9b18d9 // indirect
github.com/ssgo/log v1.7.9 // indirect github.com/ssgo/log v1.7.9 // indirect
github.com/ssgo/standard v1.7.7 // indirect github.com/ssgo/standard v1.7.7 // indirect
github.com/ssgo/tool v0.4.29 // indirect github.com/ssgo/tool v0.4.29 // indirect
golang.org/x/crypto v0.42.0 // indirect golang.org/x/crypto v0.44.0 // indirect
golang.org/x/net v0.44.0 // indirect golang.org/x/net v0.47.0 // indirect
golang.org/x/sys v0.36.0 // indirect golang.org/x/sys v0.38.0 // indirect
golang.org/x/text v0.29.0 // indirect golang.org/x/text v0.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

175
plugin.go
View File

@ -24,44 +24,51 @@ type Result struct {
} }
func init() { func init() {
config.LoadConfig(pluginName, &signerConfig) config.LoadConfig(pluginName, &apiConfigs)
Config(signerConfig) for k, v := range apiConfigs {
Config(k, *v, nil)
}
obj := map[string]any{ obj := map[string]any{
"config": Config, "config": Config,
"getConfigVersion": GetConfigVersion,
"makeApi": MakeApi,
"registerSigner": RegisterSigner, "registerSigner": RegisterSigner,
"getSignerVersion": GetSignerVersion,
"sortParams": SortParams, "sortParams": SortParams,
} }
for signer := range signerConfig { // TODO 动态更新配置时无法重新生成obj预处理配置生成Action增加通用的Call方法
cfg := signerConfig[signer] for apiName := range apiConfigs {
o := map[string]any{} // cfg := signerConfig[signer]
o["do"] = MakeAction(signer, nil) // o := map[string]any{}
o["get"] = MakeAction(signer, map[string]any{ // o["do"] = MakeAction(signer, nil)
"method": "GET", // o["get"] = MakeAction(signer, map[string]any{
}) // "method": "GET",
o["post"] = MakeAction(signer, map[string]any{ // })
"method": "POST", // o["post"] = MakeAction(signer, map[string]any{
}) // "method": "POST",
o["put"] = MakeAction(signer, map[string]any{ // })
"method": "PUT", // o["put"] = MakeAction(signer, map[string]any{
}) // "method": "PUT",
o["delete"] = MakeAction(signer, map[string]any{ // })
"method": "DELETE", // o["delete"] = MakeAction(signer, map[string]any{
}) // "method": "DELETE",
o["head"] = MakeAction(signer, map[string]any{ // })
"method": "HEAD", // o["head"] = MakeAction(signer, map[string]any{
}) // "method": "HEAD",
o["options"] = MakeAction(signer, map[string]any{ // })
"method": "OPTIONS", // o["options"] = MakeAction(signer, map[string]any{
}) // "method": "OPTIONS",
// })
// o["version"] = (*cfg)["_version"]
actions := map[string]map[string]any{} // actions := map[string]map[string]any{}
u.Convert((*cfg)["actions"], &actions) // u.Convert((*cfg)["actions"], &actions)
for k, v := range actions { // for k, v := range actions {
o[k] = MakeAction(signer, v) // o[k] = MakeAction(signer, v)
} // }
obj[signer] = o obj[apiName] = MakeApi(apiName)
} }
tsCode := gojs.MakeTSCode(obj) tsCode := gojs.MakeTSCode(obj)
@ -72,12 +79,61 @@ func init() {
}, },
TsCode: tsCode, TsCode: tsCode,
Desc: pluginName, Desc: pluginName,
JsCode: `
let $MOD$_obj = $MOD$
$MOD$ = new Proxy($MOD$_obj, {
get(target, prop) {
if(['config', 'getConfigVersion', 'registerSigner', 'getSignerVersion', 'sortParams'].indexOf(prop) >= 0) {
return target[prop]
}
let o = target[prop]
let curVer = o && o.version || 0
if(curVer == 0 || curVer != $MOD$_obj.getConfigVersion(prop)){
o = $MOD$_obj.makeApi(prop)
target[prop] = o
}
return o
}
})
`,
}) })
} }
func MakeAction(signer string, actionCfg map[string]any) func(req *Request) (*Result, error) { func MakeApi(apiName string) map[string]any {
cfg := &SignerConfig{data: map[string]any{}} cfg := apiConfigs[apiName]
if c := signerConfig[signer]; c != nil { o := map[string]any{}
o["do"] = MakeAction(apiName, "", nil)
o["get"] = MakeAction(apiName, "get", map[string]any{
"method": "GET",
})
o["post"] = MakeAction(apiName, "post", map[string]any{
"method": "POST",
})
o["put"] = MakeAction(apiName, "put", map[string]any{
"method": "PUT",
})
o["delete"] = MakeAction(apiName, "delete", map[string]any{
"method": "DELETE",
})
o["head"] = MakeAction(apiName, "head", map[string]any{
"method": "HEAD",
})
o["options"] = MakeAction(apiName, "options", map[string]any{
"method": "OPTIONS",
})
o["version"] = (*cfg)["_version"]
actions := map[string]map[string]any{}
u.Convert((*cfg)["actions"], &actions)
for k, v := range actions {
o[k] = MakeAction(apiName, k, v)
}
return o
}
func MakeAction(apiName, actionName string, actionCfg map[string]any) func(req *Request, vm *goja.Runtime) (*Result, error) {
cfg := &ApiConfig{data: map[string]any{}}
if c := apiConfigs[apiName]; c != nil {
u.Convert(c, cfg.data) u.Convert(c, cfg.data)
delete(cfg.data, "actions") delete(cfg.data, "actions")
} }
@ -104,7 +160,15 @@ func MakeAction(signer string, actionCfg map[string]any) func(req *Request) (*Re
defaultUrl = cfg.String("url", "") defaultUrl = cfg.String("url", "")
} }
return func(req *Request) (*Result, error) { actionFullName := apiName
if actionName != "" {
actionFullName += "." + actionName
}
actionsLock.Lock()
actionConfigs[actionFullName] = cfg
actionsLock.Unlock()
return func(req *Request, vm *goja.Runtime) (*Result, error) {
if req == nil { if req == nil {
req = &Request{} req = &Request{}
} }
@ -199,7 +263,7 @@ func MakeAction(signer string, actionCfg map[string]any) func(req *Request) (*Re
} }
} }
data, resp, err := Do(cfg, req1) data, resp, err := Do(actionFullName, req1, vm)
headers := map[string]string{} headers := map[string]string{}
statusCode := 0 statusCode := 0
status := "" status := ""
@ -219,19 +283,46 @@ func MakeAction(signer string, actionCfg map[string]any) func(req *Request) (*Re
} }
} }
func Config(cfg map[string]*map[string]any) { // func Config(cfg map[string]*map[string]any) {
for k, v := range cfg { // for k, v := range cfg {
if u.String((*v)["signer"]) == "" { // if u.String((*v)["signer"]) == "" {
(*v)["signer"] = k // (*v)["signer"] = k
// }
// // 尝试解密配置
// decryptConfig(reflect.ValueOf(v))
// makeConfigVar((*v), reflect.ValueOf(v))
// confLock.Lock()
// signerConfig[k] = v
// confLock.Unlock()
// }
// }
func Config(name string, cfg map[string]any, version *uint64) {
ver := u.Uint64(version)
if ver == 0 {
ver = 1
} }
cfg["_version"] = ver
// 尝试解密配置 // 尝试解密配置
decryptConfig(reflect.ValueOf(v)) cfgV := reflect.ValueOf(cfg)
makeConfigVar((*v), reflect.ValueOf(v)) decryptConfig(cfgV)
makeConfigVar(cfg, cfgV)
confLock.Lock() confLock.Lock()
signerConfig[k] = v apiConfigs[name] = &cfg
confLock.Unlock() confLock.Unlock()
}
func GetConfigVersion(name string) uint64 {
confLock.RLock()
defer confLock.RUnlock()
cfg := apiConfigs[name]
if cfg != nil {
return u.Uint64((*cfg)["_version"])
} }
return 0
} }
func decryptConfig(v reflect.Value) { func decryptConfig(v reflect.Value) {

View File

@ -14,6 +14,7 @@ import (
) )
func TestPlugin(t *testing.T) { func TestPlugin(t *testing.T) {
// fmt.Println(filepath.Join("1", "2", "", "", "3", "", "4"))
gojs.ExportForDev() gojs.ExportForDev()
for _, f := range u.ReadDirN(".") { for _, f := range u.ReadDirN(".") {
if strings.HasSuffix(f.Name, "_test.js") { if strings.HasSuffix(f.Name, "_test.js") {