refactor: 重构trustlog-sdk目录结构到trustlog/go-trustlog

- 将所有trustlog-sdk文件移动到trustlog/go-trustlog/目录
- 更新README中所有import路径从trustlog-sdk改为go-trustlog
- 更新cookiecutter配置文件中的项目名称
- 更新根目录.lefthook.yml以引用新位置的配置
- 添加go.sum文件到版本控制
- 删除过时的示例文件

这次重构与trustlog-server保持一致的目录结构,
为未来支持多语言SDK(Python、Java等)预留空间。
This commit is contained in:
ryan
2025-12-22 13:37:57 +08:00
commit d313449c5c
87 changed files with 20622 additions and 0 deletions

577
api/model/operation.go Normal file
View File

@@ -0,0 +1,577 @@
package model
import (
"context"
"errors"
"fmt"
"strings"
"time"
"go.yandata.net/iod/iod/trustlog-sdk/api/logger"
"go.yandata.net/iod/iod/trustlog-sdk/internal/helpers"
)
//
// ===== 操作来源类型 =====
//
// Source 表示操作来源用于区分不同系统模块IRP、DOIP
type Source string
const (
OpSourceIRP Source = "IRP"
OpSourceDOIP Source = "DOIP"
)
//
// ===== 操作类型枚举 =====
//
// Type 表示操作的具体类型。
type Type string
// DOIP 操作类型枚举。
const (
OpTypeHello Type = "Hello"
OpTypeRetrieve Type = "Retrieve"
OpTypeCreate Type = "Create"
OpTypeDelete Type = "Delete"
OpTypeUpdate Type = "Update"
OpTypeSearch Type = "Search"
OpTypeListOperations Type = "ListOperations"
)
// IRP 操作类型枚举。
const (
OpTypeOCReserved Type = "OC_RESERVED"
OpTypeOCResolution Type = "OC_RESOLUTION"
OpTypeOCGetSiteInfo Type = "OC_GET_SITEINFO"
OpTypeOCCreateHandle Type = "OC_CREATE_HANDLE"
OpTypeOCDeleteHandle Type = "OC_DELETE_HANDLE"
OpTypeOCAddValue Type = "OC_ADD_VALUE"
OpTypeOCRemoveValue Type = "OC_REMOVE_VALUE"
OpTypeOCModifyValue Type = "OC_MODIFY_VALUE"
OpTypeOCListHandle Type = "OC_LIST_HANDLE"
OpTypeOCListNA Type = "OC_LIST_NA"
OpTypeOCResolutionDOID Type = "OC_RESOLUTION_DOID"
OpTypeOCCreateDOID Type = "OC_CREATE_DOID"
OpTypeOCDeleteDOID Type = "OC_DELETE_DOID"
OpTypeOCUpdateDOID Type = "OC_UPDATE_DOID"
OpTypeOCBatchCreateDOID Type = "OC_BATCH_CREATE_DOID"
OpTypeOCResolutionDOIDRecursive Type = "OC_RESOLUTION_DOID_RECURSIVE"
OpTypeOCGetUsers Type = "OC_GET_USERS"
OpTypeOCGetRepos Type = "OC_GET_REPOS"
OpTypeOCVerifyIRS Type = "OC_VERIFY_IRS"
OpTypeOCResolveGRS Type = "OC_RESOLVE_GRS"
OpTypeOCCreateOrgGRS Type = "OC_CREATE_ORG_GRS"
OpTypeOCUpdateOrgGRS Type = "OC_UPDATE_ORG_GRS"
OpTypeOCDeleteOrgGRS Type = "OC_DELETE_ORG_GRS"
OpTypeOCSyncOrgIRSParent Type = "OC_SYNC_ORG_IRS_PARENT"
OpTypeOCUpdateOrgIRSParent Type = "OC_UPDATE_ORG_IRS_PARENT"
OpTypeOCDeleteOrgIRSParent Type = "OC_DELETE_ORG_IRS_PARENT"
OpTypeOCChallengeResponse Type = "OC_CHALLENGE_RESPONSE"
OpTypeOCVerifyChallenge Type = "OC_VERIFY_CHALLENGE"
OpTypeOCSessionSetup Type = "OC_SESSION_SETUP"
OpTypeOCSessionTerminate Type = "OC_SESSION_TERMINATE"
OpTypeOCSessionExchangeKey Type = "OC_SESSION_EXCHANGEKEY"
OpTypeOCVerifyRouter Type = "OC_VERIFY_ROUTER"
OpTypeOCQueryRouter Type = "OC_QUERY_ROUTER"
)
//
// ===== 操作类型检索工具 =====
//
// allOpTypes 存储不同来源的操作类型列表,用于快速查找和验证。
//
//nolint:gochecknoglobals // 全局常量映射用于操作类型查找
var allOpTypes = map[Source][]Type{
OpSourceDOIP: {
OpTypeHello, OpTypeRetrieve, OpTypeCreate,
OpTypeDelete, OpTypeUpdate, OpTypeSearch,
OpTypeListOperations,
},
OpSourceIRP: {
OpTypeOCReserved, OpTypeOCResolution, OpTypeOCGetSiteInfo,
OpTypeOCCreateHandle, OpTypeOCDeleteHandle, OpTypeOCAddValue,
OpTypeOCRemoveValue, OpTypeOCModifyValue, OpTypeOCListHandle,
OpTypeOCListNA, OpTypeOCResolutionDOID, OpTypeOCCreateDOID,
OpTypeOCDeleteDOID, OpTypeOCUpdateDOID, OpTypeOCBatchCreateDOID,
OpTypeOCResolutionDOIDRecursive, OpTypeOCGetUsers, OpTypeOCGetRepos,
OpTypeOCVerifyIRS, OpTypeOCResolveGRS, OpTypeOCCreateOrgGRS,
OpTypeOCUpdateOrgGRS, OpTypeOCDeleteOrgGRS, OpTypeOCSyncOrgIRSParent,
OpTypeOCUpdateOrgIRSParent, OpTypeOCDeleteOrgIRSParent,
OpTypeOCChallengeResponse, OpTypeOCVerifyChallenge,
OpTypeOCSessionSetup, OpTypeOCSessionTerminate,
OpTypeOCSessionExchangeKey, OpTypeOCVerifyRouter, OpTypeOCQueryRouter,
},
}
// GetOpTypesBySource 返回指定来源的可用操作类型列表。
func GetOpTypesBySource(source Source) []Type {
return allOpTypes[source]
}
// IsValidOpType 判断指定操作类型在给定来源下是否合法。
func IsValidOpType(source Source, opType Type) bool {
for _, t := range GetOpTypesBySource(source) {
if t == opType {
return true
}
}
return false
}
//
// ===== 操作记录结构 =====
//
// Operation 表示一次完整的操作记录。
// 用于记录系统中的操作行为,包含操作元数据、数据标识、操作者信息以及请求/响应的哈希值。
type Operation struct {
OpID string `json:"opId" validate:"max=32"`
Timestamp time.Time `json:"timestamp" validate:"required"`
OpSource Source `json:"opSource" validate:"required,oneof=IRP DOIP"`
OpType Type `json:"opType" validate:"required"`
DoPrefix string `json:"doPrefix" validate:"required,max=512"`
DoRepository string `json:"doRepository" validate:"required,max=512"`
Doid string `json:"doid" validate:"required,max=512"`
ProducerID string `json:"producerId" validate:"required,max=512"`
OpActor string `json:"opActor" validate:"max=64"`
RequestBodyHash *string `json:"requestBodyHash" validate:"omitempty,max=128"`
ResponseBodyHash *string `json:"responseBodyHash" validate:"omitempty,max=128"`
Ack func() bool `json:"-"`
Nack func() bool `json:"-"`
binary []byte
}
//
// ===== 构造函数 =====
//
// NewFullOperation 创建包含所有字段的完整 Operation。
// 自动完成哈希计算和字段校验,确保创建的 Operation 是完整且有效的。
func NewFullOperation(
opSource Source,
opType Type,
doPrefix, doRepository, doid string,
producerID string,
opActor string,
requestBody, responseBody interface{},
timestamp time.Time,
) (*Operation, error) {
log := logger.GetGlobalLogger()
log.Debug("Creating new full operation",
"opSource", opSource,
"opType", opType,
"doPrefix", doPrefix,
"doRepository", doRepository,
"doid", doid,
"producerID", producerID,
"opActor", opActor,
)
op := &Operation{
Timestamp: timestamp,
OpSource: opSource,
OpType: opType,
DoPrefix: doPrefix,
DoRepository: doRepository,
Doid: doid,
ProducerID: producerID,
OpActor: opActor,
}
log.Debug("Setting request body hash")
if err := op.RequestBodyFlexible(requestBody); err != nil {
log.Error("Failed to set request body hash",
"error", err,
)
return nil, err
}
log.Debug("Setting response body hash")
if err := op.ResponseBodyFlexible(responseBody); err != nil {
log.Error("Failed to set response body hash",
"error", err,
)
return nil, err
}
log.Debug("Checking and initializing operation")
if err := op.CheckAndInit(); err != nil {
log.Error("Failed to check and init operation",
"error", err,
)
return nil, err
}
log.Debug("Full operation created successfully",
"opID", op.OpID,
)
return op, nil
}
//
// ===== 接口实现 =====
//
func (o *Operation) Key() string {
return o.OpID
}
// OperationHashData 实现 HashData 接口,用于存储 Operation 的哈希计算结果。
type OperationHashData struct {
key string
hash string
}
func (o OperationHashData) Key() string {
return o.key
}
func (o OperationHashData) Hash() string {
return o.hash
}
func (o OperationHashData) Type() HashType {
return Sha256Simd
}
// DoHash 计算 Operation 的整体哈希值,用于数据完整性验证。
// 哈希基于序列化后的二进制数据计算,确保操作记录的不可篡改性。
func (o *Operation) DoHash(_ context.Context) (HashData, error) {
log := logger.GetGlobalLogger()
log.Debug("Computing hash for operation",
"opID", o.OpID,
)
hashTool := GetHashTool(Sha256Simd)
binary, err := o.MarshalBinary()
if err != nil {
log.Error("Failed to marshal operation for hash",
"error", err,
"opID", o.OpID,
)
return nil, fmt.Errorf("failed to marshal operation: %w", err)
}
log.Debug("Computing hash bytes",
"opID", o.OpID,
"binaryLength", len(binary),
)
hash, err := hashTool.HashBytes(binary)
if err != nil {
log.Error("Failed to compute hash",
"error", err,
"opID", o.OpID,
)
return nil, fmt.Errorf("failed to compute hash: %w", err)
}
log.Debug("Hash computed successfully",
"opID", o.OpID,
"hash", hash,
)
return OperationHashData{
key: o.OpID,
hash: hash,
}, nil
}
//
// ===== CBOR 序列化相关 =====
//
// operationData 用于 CBOR 序列化/反序列化的中间结构。
// 排除函数字段和缓存字段,仅包含可序列化的数据字段。
type operationData struct {
OpID *string `cbor:"opId"`
Timestamp *time.Time `cbor:"timestamp"`
OpSource *Source `cbor:"opSource"`
OpType *Type `cbor:"opType"`
DoPrefix *string `cbor:"doPrefix"`
DoRepository *string `cbor:"doRepository"`
Doid *string `cbor:"doid"`
ProducerID *string `cbor:"producerId"`
OpActor *string `cbor:"opActor"`
RequestBodyHash *string `cbor:"requestBodyHash"`
ResponseBodyHash *string `cbor:"responseBodyHash"`
}
// toOperationData 将 Operation 转换为 operationData用于序列化。
func (o *Operation) toOperationData() *operationData {
return &operationData{
OpID: &o.OpID,
Timestamp: &o.Timestamp,
OpSource: &o.OpSource,
OpType: &o.OpType,
DoPrefix: &o.DoPrefix,
DoRepository: &o.DoRepository,
Doid: &o.Doid,
ProducerID: &o.ProducerID,
OpActor: &o.OpActor,
RequestBodyHash: o.RequestBodyHash,
ResponseBodyHash: o.ResponseBodyHash,
}
}
// fromOperationData 从 operationData 填充 Operation用于反序列化。
func (o *Operation) fromOperationData(opData *operationData) {
if opData == nil {
return
}
if opData.OpID != nil {
o.OpID = *opData.OpID
}
if opData.Timestamp != nil {
o.Timestamp = *opData.Timestamp
}
if opData.OpSource != nil {
o.OpSource = *opData.OpSource
}
if opData.OpType != nil {
o.OpType = *opData.OpType
}
if opData.DoPrefix != nil {
o.DoPrefix = *opData.DoPrefix
}
if opData.DoRepository != nil {
o.DoRepository = *opData.DoRepository
}
if opData.Doid != nil {
o.Doid = *opData.Doid
}
if opData.ProducerID != nil {
o.ProducerID = *opData.ProducerID
}
if opData.OpActor != nil {
o.OpActor = *opData.OpActor
}
if opData.RequestBodyHash != nil {
hash := *opData.RequestBodyHash
o.RequestBodyHash = &hash
}
if opData.ResponseBodyHash != nil {
hash := *opData.ResponseBodyHash
o.ResponseBodyHash = &hash
}
}
// MarshalBinary 将 Operation 序列化为 CBOR 格式的二进制数据。
// 实现 encoding.BinaryMarshaler 接口。
// 使用 Canonical CBOR 编码确保序列化结果的一致性,使用缓存机制避免重复序列化。
func (o *Operation) MarshalBinary() ([]byte, error) {
log := logger.GetGlobalLogger()
log.Debug("Marshaling operation to CBOR binary",
"opID", o.OpID,
)
if o.binary != nil {
log.Debug("Using cached binary data",
"opID", o.OpID,
)
return o.binary, nil
}
opData := o.toOperationData()
log.Debug("Marshaling operation data to canonical CBOR",
"opID", o.OpID,
)
binary, err := helpers.MarshalCanonical(opData)
if err != nil {
log.Error("Failed to marshal operation to CBOR",
"error", err,
"opID", o.OpID,
)
return nil, fmt.Errorf("failed to marshal operation to CBOR: %w", err)
}
o.binary = binary
log.Debug("Operation marshaled successfully",
"opID", o.OpID,
"binaryLength", len(binary),
)
return binary, nil
}
// GetProducerID 返回 ProducerID实现 Trustlog 接口。
func (o *Operation) GetProducerID() string {
return o.ProducerID
}
// UnmarshalBinary 从 CBOR 格式的二进制数据反序列化为 Operation。
// 实现 encoding.BinaryUnmarshaler 接口。
func (o *Operation) UnmarshalBinary(data []byte) error {
log := logger.GetGlobalLogger()
log.Debug("Unmarshaling operation from CBOR binary",
"dataLength", len(data),
)
if len(data) == 0 {
log.Error("Data is empty")
return errors.New("data is empty")
}
opData := &operationData{}
log.Debug("Unmarshaling operation data from CBOR")
if err := helpers.Unmarshal(data, opData); err != nil {
log.Error("Failed to unmarshal operation from CBOR",
"error", err,
)
return fmt.Errorf("failed to unmarshal operation from CBOR: %w", err)
}
o.fromOperationData(opData)
o.binary = data
log.Debug("Operation unmarshaled successfully",
"opID", o.OpID,
)
return nil
}
//
// ===== 哈希设置方法 =====
//
// setBodyHashFlexible 根据输入数据类型计算哈希,支持 string 和 []byte。
// 使用固定的 Sha256Simd 算法。
// 如果输入为 nil 或空,则目标指针设置为 nil表示该字段未设置。
func (o *Operation) setBodyHashFlexible(data interface{}, target **string) error {
log := logger.GetGlobalLogger()
log.Debug("Setting body hash flexible",
"opID", o.OpID,
"dataType", fmt.Sprintf("%T", data),
)
if data == nil {
log.Debug("Data is nil, setting target to nil")
*target = nil
return nil
}
hashTool := GetHashTool(Sha256Simd)
var raw []byte
switch v := data.(type) {
case string:
if v == "" {
log.Debug("String data is empty, setting target to nil")
*target = nil
return nil
}
raw = []byte(v)
log.Debug("Converting string to bytes",
"stringLength", len(v),
)
case []byte:
if len(v) == 0 {
log.Debug("Byte data is empty, setting target to nil")
*target = nil
return nil
}
raw = v
log.Debug("Using byte data directly",
"byteLength", len(v),
)
default:
log.Error("Unsupported data type",
"dataType", fmt.Sprintf("%T", v),
)
return fmt.Errorf("unsupported data type %T", v)
}
log.Debug("Computing hash for body data",
"dataLength", len(raw),
)
hash, err := hashTool.HashBytes(raw)
if err != nil {
log.Error("Failed to compute hash",
"error", err,
)
return err
}
*target = &hash
log.Debug("Body hash set successfully",
"hash", hash,
)
return nil
}
// RequestBodyFlexible 设置请求体哈希值。
// 支持 string 和 []byte 类型nil 或空值会将 RequestBodyHash 设置为 nil。
func (o *Operation) RequestBodyFlexible(data interface{}) error {
return o.setBodyHashFlexible(data, &o.RequestBodyHash)
}
// ResponseBodyFlexible 设置响应体哈希值。
// 支持 string 和 []byte 类型nil 或空值会将 ResponseBodyHash 设置为 nil。
func (o *Operation) ResponseBodyFlexible(data interface{}) error {
return o.setBodyHashFlexible(data, &o.ResponseBodyHash)
}
//
// ===== 链式调用支持 =====
//
// WithRequestBody 设置请求体哈希并返回自身,支持链式调用。
func (o *Operation) WithRequestBody(data []byte) *Operation {
_ = o.RequestBodyFlexible(data)
return o
}
// WithResponseBody 设置响应体哈希并返回自身,支持链式调用。
func (o *Operation) WithResponseBody(data []byte) *Operation {
_ = o.ResponseBodyFlexible(data)
return o
}
//
// ===== 初始化与验证 =====
//
// CheckAndInit 校验并初始化 Operation。
// 自动填充缺失字段OpID、OpActor执行业务逻辑验证doid 格式),
// 字段非空验证由 validate 标签处理。
func (o *Operation) CheckAndInit() error {
log := logger.GetGlobalLogger()
log.Debug("Checking and initializing operation",
"opSource", o.OpSource,
"opType", o.OpType,
"doid", o.Doid,
)
if o.OpID == "" {
o.OpID = helpers.NewUUIDv7()
log.Debug("Generated new OpID",
"opID", o.OpID,
)
}
if o.OpActor == "" {
o.OpActor = "SYSTEM"
log.Debug("Set default OpActor to SYSTEM")
}
expectedPrefix := fmt.Sprintf("%s/%s", o.DoPrefix, o.DoRepository)
if !strings.HasPrefix(o.Doid, expectedPrefix) {
log.Error("Doid format validation failed",
"doid", o.Doid,
"expectedPrefix", expectedPrefix,
)
return fmt.Errorf("doid must start with '%s'", expectedPrefix)
}
log.Debug("Validating operation struct")
if err := helpers.GetValidator().Struct(o); err != nil {
log.Error("Operation validation failed",
"error", err,
"opID", o.OpID,
)
return err
}
log.Debug("Operation checked and initialized successfully",
"opID", o.OpID,
)
return nil
}