logo
Public
0
0
WeChat Login

kvdb - EdgeOne Pages KV Go SDK

kvdb 是 EdgeOne CLI 内置 kv-client 的 Go 语言移植版,提供完整的控制面与数据面链路支持,可作为生产级 Go SDK 嵌入各类服务。

目录


特性

  • 协议兼容:与现网 CLI 的控制面 API、AES-256-CBC 解密算法、数据面 RESP 命令保持完全兼容
  • 生产可用:单连接复用、互斥锁保证并发安全、超时可控、网络异常自动断链并重连
  • 零第三方依赖:仅使用 Go 标准库,无额外传递依赖,可嵌入受限环境
  • 多种绑定获取方式:支持控制面 API 拉取、环境变量注入两种模式
  • 完整可测性
    • 单元测试:绑定解析、环境变量解析、控制面解密逻辑
    • 集成测试:本地 mock RESP 服务验证数据面协议
    • 端到端测试:真实 EdgeOne 环境联调

架构概览

两条主要链路:

  1. 控制面链路:通过 EdgeOne Pages API 拉取并解密 KV 绑定配置
  2. 数据面链路:通过 RESP/TCP 协议与 KV 存储服务交互

快速开始

方式一:通过控制面拉取绑定(推荐)

package main import ( "context" "log" "time" kv "cnb.cool/svn/kv" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() // 1. 直接打开单个 KV client client, err := kv.OpenGlobalClient( ctx, "YOUR_API_TOKEN", kv.WithPlaneProjectID("pages-xxxx"), kv.WithPlaneBindingName("kvdb"), kv.WithPlaneClientOptions( kv.WithConnectTimeout(10 * time.Second), kv.WithCommandTimeout(10 * time.Second), ), ) if err != nil { log.Fatal(err) } defer client.Close() // 2. 读写数据 if err := client.PutString(ctx, "hello", "world"); err != nil { log.Fatal(err) } value, found, err := client.GetString(ctx, "hello") if err != nil { log.Fatal(err) } if found { log.Println("hello =", value) } }

方式二:从环境变量读取绑定

适用于 EdgeOne Pages 部署环境,绑定信息通过 EO_KV_BINDINGS 环境变量自动注入:

package main import ( "context" "log" "time" kv "cnb.cool/svn/kv" ) func main() { // 从 EO_KV_BINDINGS 环境变量加载注册表 registry, ok, err := kv.LoadRegistryFromEnv() if err != nil { log.Fatal(err) } if !ok { log.Fatal("EO_KV_BINDINGS 环境变量未设置") } defer registry.Close() ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() client, err := registry.Client("kvdb") if err != nil { log.Fatal(err) } value, found, err := client.GetString(ctx, "hello") // ... }

安装

作为 Go 模块依赖

go get cnb.cool/svn/kv@latest

克隆源码开发

git clone https://cnb.cool/svn/kv cd kv go test ./...

模块信息:

  • Module Pathcnb.cool/svn/kv
  • Package Namekv
  • Go Version:1.26+
  • 依赖:仅 Go 标准库

核心 API

控制面 API(PlaneClient

方法说明
OpenGlobalClient(ctx, token, opts...)直接通过国际站打开单个 KV client
OpenChinaClient(ctx, token, opts...)直接通过中国站打开单个 KV client
NewChinaPlaneClient(token, opts...)创建默认指向中国站的控制面客户端
NewGlobalPlaneClient(token, opts...)创建默认指向国际站的控制面客户端
NewPlaneClient(region, token, opts...)创建控制面客户端
(*PlaneClient).FetchBindings(ctx, projectID...)拉取项目的 KV 绑定列表;若已配置默认 ProjectId,可省略参数
(*PlaneClient).ResolveBinding(ctx, selector)在默认项目内解析单个绑定
(*PlaneClient).OpenClient(ctx, selector, opts...)直接打开单个 KV client
(*PlaneClient).ListProjects(ctx)枚举可见的 Pages 项目
(*PlaneClient).FindProjectByNamespace(ctx, namespace)通过绑定名/namespace 反推项目信息
(*PlaneClient).InferProjectIDByNamespace(ctx, namespace)通过绑定名/namespace 反推 ProjectID
DecryptBindings(encrypted)解密控制面返回的加密绑定数据

数据面 API(Client

方法说明
NewClient(binding, opts...)创建数据面客户端
(*Client).Get(ctx, key)读取键值,返回 []byte
(*Client).GetString(ctx, key)读取键值,返回 string
(*Client).GetJSON(ctx, key, target)读取并反序列化 JSON
(*Client).Put(ctx, key, value)写入原始字节
(*Client).PutString(ctx, key, value)写入字符串
(*Client).PutJSON(ctx, key, value)序列化并写入 JSON
(*Client).Delete(ctx, key)删除键
(*Client).List(ctx, opts)按前缀列举键(支持分页)
(*Client).Close()关闭客户端,释放连接
(*Client).Binding()获取当前绑定的配置副本

注册表 API(Registry

方法说明
NewRegistry(bindings, opts...)从绑定列表创建注册表
(*Registry).Names()获取所有已注册绑定名(排序)
(*Registry).Binding(name)获取指定绑定的配置
(*Registry).Client(name)获取指定绑定的客户端(懒创建)
(*Registry).Close()关闭注册表内所有客户端

引导 API(bootstrap

函数说明
LoadRegistryFromEnv(opts...)EO_KV_BINDINGS 加载注册表
ConsumeRegistryFromEnv(opts...)加载并清除环境变量
FetchRegistry(ctx, region, token, projectID, cpOpts, clientOpts...)通过控制面拉取并创建注册表

客户端选项

// 设置建连超时(默认 10s) kv.WithConnectTimeout(15 * time.Second) // 设置单条命令超时(默认 10s) kv.WithCommandTimeout(15 * time.Second) // 注入日志器(用于调试) kv.WithLogger(customLogger)

控制面选项

// 覆盖默认 API 地址 kv.WithPlaneBaseURL("https://custom-api.example.com") // 注入自定义 HTTP 客户端 kv.WithPlaneHTTPClient(customHTTPClient) // 预设默认 ProjectId;之后可直接 client.FetchBindings(ctx) kv.WithPlaneProjectID("pages-xxxx") // 预设默认 BindingName;之后可直接 client.OpenClient(ctx, "") kv.WithPlaneBindingName("kvdb") // 手动覆盖地域(优先级高于 NewPlaneClient 第一个参数) kv.WithPlaneRegion(kv.RegionGlobal) // 设置默认 HTTP 超时 kv.WithPlaneTimeout(20 * time.Second) // 设置自定义 User-Agent kv.WithPlaneUserAgent("my-app/1.0") // 调整项目枚举分页大小(用于 ProjectId 反推) kv.WithPlaneProjectPageSize(200) // 为高阶入口预设数据面 Client 参数 kv.WithPlaneClientOptions( kv.WithConnectTimeout(10 * time.Second), kv.WithCommandTimeout(10 * time.Second), )

推荐写法:

client, err := kv.OpenGlobalClient( ctx, "YOUR_API_TOKEN", kv.WithPlaneProjectID("pages-xxxx"), kv.WithPlaneBindingName("kvdb"), kv.WithPlaneClientOptions( kv.WithConnectTimeout(10 * time.Second), kv.WithCommandTimeout(10 * time.Second), ), ) if err != nil { log.Fatal(err) } defer client.Close()

若你的主环境在中国站,则对应写法是:

client, err := kv.OpenChinaClient( ctx, "YOUR_API_TOKEN", kv.WithPlaneProjectID("pages-xxxx"), kv.WithPlaneBindingName("kvdb"), )

如果你还想保留控制面对象本身,再使用:

planeClient, err := kv.NewGlobalPlaneClient( "YOUR_API_TOKEN", kv.WithPlaneProjectID("pages-xxxx"), kv.WithPlaneBindingName("kvdb"), ) if err != nil { log.Fatal(err) } client, err := planeClient.OpenClient(ctx, "")

测试

运行全部测试

cd kv go test ./...

启用竞态检测

go test -race ./...

端到端测试(需要真实 EdgeOne 环境)

export EDGEONE_KV_E2E=1 export EDGEONE_KV_API_TOKEN='YOUR_TOKEN' export EDGEONE_KV_REGION='global' export EDGEONE_KV_PROJECT_ID='pages-xxxx' export EDGEONE_KV_BINDING_NAME='kvdb' go test -run TestE2EEdgeOne -v

测试覆盖内容

端到端测试会自动执行:

  1. 通过控制面拉取绑定
  2. 选择目标绑定
  3. 写入唯一测试键
  4. 读取并校验返回值
  5. 按前缀列举确认可见性
  6. 清理测试数据

文档索引

文档说明
README.md项目说明与快速开始(本文档)
MANUAL.md完整使用手册
DESIGN.md架构设计与实现细节

相关链接

  • Module Pathcnb.cool/svn/kv
  • CLI 工具cmd/kvdb-cli/main.go
  • EdgeOne Pages API(国际站)https://pages-api.edgeone.ai/v1
  • EdgeOne Pages API(中国站)https://pages-api.cloud.tencent.com/v1

About

No description, topics, or website provided.
Language
Go100%