api/action.go

218 lines
5.1 KiB
Go
Raw Normal View History

package api
import (
"reflect"
"unsafe"
"apigo.cc/go/cast"
"apigo.cc/go/safe"
)
// Action 是所有接口的基础标识接口
type Action interface {
ActionName() string // 例如: "tencent.sms.send"
}
// SignerAction 定义需要签名的动作
type SignerAction interface {
SignerName() string // 例如: "tc3"
}
// ConfigurableAction 定义可以提供默认硬编码配置的动作
type ConfigurableAction interface {
Config() map[string]any
}
// URLAction 定义显式指定 URL 的动作
type URLAction interface {
GetURL() string
}
// MethodAction 定义显式指定方法的动作
type MethodAction interface {
GetMethod() string // 例如: "GET"
}
// ValidatableAction 定义支持自我校验的动作
type ValidatableAction interface {
Validate() error
}
// FormatAction 定义请求体格式
type FormatAction interface {
GetFormat() string // 返回: "json", "form", "multipart"
}
// ActionRegistry 存储已注册的 Action 模板或类型
var actionRegistry = make(map[string]any)
// RegisterAction 注册 API 动作。
// definition 可以是一个结构体实例(用作类型模板)或一个 map[string]any用作动态定义
func RegisterAction(name string, definition any) {
if definition == nil {
return
}
t := reflect.TypeOf(definition)
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() == reflect.Struct {
actionRegistry[name] = t
} else if m, ok := definition.(map[string]any); ok {
ga := &GenericAction{
name: name,
url: cast.String(m["url"]),
method: cast.String(m["method"]),
signer: cast.String(m["signer"]),
format: cast.String(m["format"]),
payload: make(map[string]any),
}
if p, ok := m["payload"].(map[string]any); ok {
ga.payload = p
}
actionRegistry[name] = ga
}
}
// GenericAction 是一个动态 Action 容器,实现了所有 API 相关接口
type GenericAction struct {
name string
url string
method string
signer string
format string
payload map[string]any
}
func (a *GenericAction) ActionName() string { return a.name }
func (a *GenericAction) SignerName() string { return a.signer }
func (a *GenericAction) GetURL() string { return a.url }
func (a *GenericAction) GetMethod() string { return a.method }
func (a *GenericAction) GetFormat() string { return a.format }
func (a *GenericAction) Config() map[string]any {
return map[string]any{
"url": a.url,
"method": a.method,
"signer": a.signer,
"format": a.format,
}
}
func (a *GenericAction) MarshalJSON() ([]byte, error) {
return cast.ToJSONBytes(a.payload)
}
// HttpRequest 内部使用的请求描述结构,供 Signer 使用
type HttpRequest struct {
Url string
Method string
headers map[string]string
Payload any
wipeableBuffers [][]byte // 追踪需要安全擦除的敏感缓冲区
}
// GetHeader 获取指定 Header 的值
func (r *HttpRequest) GetHeader(key string) string {
if r == nil || r.headers == nil {
return ""
}
return r.headers[key]
}
// Close 物理覆盖并清除所有关联的敏感缓冲区,确保内存中不再留存明文
func (r *HttpRequest) Close() {
if r == nil {
return
}
// 擦除缓冲区
for _, buffer := range r.wipeableBuffers {
safe.ZeroMemory(buffer)
}
r.wipeableBuffers = nil
}
// SetHeader 提供无感知的安全 Header 设置功能。支持传入多个参数进行自动拼接。
// 如果参数中包含 *safe.SafeBuf, *safe.SecretPlaintext 或 []byte (标记为敏感)
// 整个生成的 Header 缓冲区都将被注册用于后置物理擦除。
// 安全的拼接与转换(如 safe.Concat, safe.Base64建议使用 safe 包提供的返回 *safe.SafeBuf 的方法。
func (r *HttpRequest) SetHeader(key string, values ...any) {
if len(values) == 0 {
return
}
if r.headers == nil {
r.headers = make(map[string]string)
}
// 1. 计算总长度并识别是否有敏感数据
totalLen := 0
isSensitive := false
for _, v := range values {
switch t := v.(type) {
case string:
totalLen += len(t)
case []byte:
totalLen += len(t)
isSensitive = true
case *safe.SafeBuf:
if t == nil {
continue
}
p := t.Open()
totalLen += len(p.Data)
p.Close()
isSensitive = true
case *safe.SecretPlaintext:
if t == nil {
continue
}
totalLen += len(t.Data)
isSensitive = true
default:
s := cast.String(v)
totalLen += len(s)
}
}
// 2. 分配单一缓冲区进行拼接
buf := make([]byte, totalLen)
pos := 0
for _, v := range values {
switch t := v.(type) {
case string:
pos += copy(buf[pos:], t)
case []byte:
pos += copy(buf[pos:], t)
case *safe.SafeBuf:
if t == nil {
continue
}
p := t.Open()
pos += copy(buf[pos:], p.Data)
p.Close()
case *safe.SecretPlaintext:
if t == nil {
continue
}
pos += copy(buf[pos:], t.Data)
default:
pos += copy(buf[pos:], cast.String(v))
}
}
// 3. 映射到 headers 并注册清理
r.headers[key] = unsafe.String(&buf[0], len(buf))
if isSensitive {
r.wipeableBuffers = append(r.wipeableBuffers, buf)
}
}
// Result 定义 API 调用的标准返回结果
type Result struct {
2026-05-09 16:31:41 +08:00
StatusCode int
Status string
Headers map[string]string
Data any
}