Browse Source

Refactor project structure

main
ywlmac 2 months ago
parent
commit
9f5a42e0bb
  1. 15
      error.go
  2. 29
      main.go
  3. 79
      pkg/zxchainsdk/certificate.go
  4. 2
      pkg/zxchainsdk/certificate_flow.go
  5. 0
      pkg/zxchainsdk/client.go
  6. 0
      pkg/zxchainsdk/model.go
  7. 52
      pkg/zxchainsdk/sdk_client.go

15
error.go

@ -1,15 +0,0 @@
package zxchainsdk
import "errors"
var (
ErrMissingBizID = errors.New("missing biz_id")
ErrMissingContent = errors.New("missing content")
ErrMissingEvID = errors.New("missing ev_id")
ErrMissingHash = errors.New("missing hash")
ErrMissingScene = errors.New("missing scene")
ErrMissingKVFields = errors.New("missing kv fields")
ErrMissingFileName = errors.New("missing file_name")
ErrMissingQueryKey = errors.New("missing ev_id, hash or tx_id")
ErrEmptyAttestation = errors.New("empty attestation request")
)

29
examples/manual/main.go → main.go

@ -8,9 +8,21 @@ import (
"strings" "strings"
"time" "time"
"git.yuanzoo.cn/zhangzhengqiang/popi-zxl" "git.yuanzoo.cn/zhangzhengqiang/popi-zxl/pkg/zxchainsdk"
) )
const (
defaultDemoWorkPreviewURL = "https://popiart-public-1313913486.cos.ap-guangzhou.myqcloud.com/2026-05-09-6.jpg"
defaultTestEvID = "302d355f4b7911f1bf330a77039e1980"
)
func getenvDefault(key, fallback string) string {
if value := strings.TrimSpace(os.Getenv(key)); value != "" {
return value
}
return fallback
}
// loadDotEnv 加载当前目录下的 .env,方便本地测试。 // loadDotEnv 加载当前目录下的 .env,方便本地测试。
func loadDotEnv(path string) { func loadDotEnv(path string) {
file, err := os.Open(path) file, err := os.Open(path)
@ -184,12 +196,13 @@ func h4() (string, error) {
client := newClient() client := newClient()
result, err := client.CreateSimpleHashAttestationCertificate(context.Background(), zxchainsdk.SimpleHashAttestationCertificateRequest{ result, err := client.CreateSimpleHashAttestationCertificate(context.Background(), zxchainsdk.SimpleHashAttestationCertificateRequest{
UserName: "zzzzzq", // 申请用户名称 UserName: getenvDefault("ZXCHAIN_TEST_USER_NAME", "zzzzzq"), // 申请用户名称
UserID: "56142321", // 申请用户 ID UserID: getenvDefault("ZXCHAIN_TEST_USER_ID", "56142321"), // 申请用户 ID
WorkName: "测试作品", // 作品名称 WorkName: getenvDefault("ZXCHAIN_TEST_WORK_NAME", "测试作品"), // 作品名称
TaskID: "1231223", // 生成任务 ID TaskID: getenvDefault("ZXCHAIN_TEST_TASK_ID", "1231223"), // 生成任务 ID
CompletedAt: "2026.5.11 15:20:01", // 作品完成时间 CompletedAt: getenvDefault("ZXCHAIN_TEST_COMPLETED_AT", "2026.5.11 15:20:01"), // 作品完成时间
WorkPreviewURL: "https://popiart-public-1313913486.cos.ap-guangzhou.myqcloud.com/media/2026/0511/83218.jpg", // 作品预览图 URL WorkPreviewURL: getenvDefault("ZXCHAIN_WORK_PREVIEW_URL", defaultDemoWorkPreviewURL), // 作品预览图 URL
EvidenceHash: os.Getenv("ZXCHAIN_EVIDENCE_HASH"), // 可选:传入后不下载预览图计算哈希
// EvidenceHash 不传,SDK 会自动从 WorkPreviewURL 下载并计算 SM3 哈希 // EvidenceHash 不传,SDK 会自动从 WorkPreviewURL 下载并计算 SM3 哈希
CertificateStorage: &zxchainsdk.COSCertificateStorage{ CertificateStorage: &zxchainsdk.COSCertificateStorage{
@ -233,7 +246,7 @@ func main() {
log.Printf("h4 测试失败: %v", err) log.Printf("h4 测试失败: %v", err)
evID = os.Getenv("ZXCHAIN_TEST_EV_ID") evID = os.Getenv("ZXCHAIN_TEST_EV_ID")
if evID == "" { if evID == "" {
evID = "302d355f4b7911f1bf330a77039e1980" evID = defaultTestEvID
} }
log.Printf("继续使用已有 evId 测试 h3: %s", evID) log.Printf("继续使用已有 evId 测试 h3: %s", evID)
} }

79
certificate.go → pkg/zxchainsdk/certificate.go

@ -23,8 +23,8 @@ import (
) )
const ( const (
defaultCertificateBackgroundURL = "https://popiart-public-1313913486.cos.ap-guangzhou.myqcloud.com/media/2026/0511/83034.png" defaultCertificateBackgroundURL = "https://popiart-public-1313913486.cos.ap-guangzhou.myqcloud.com/media/2026/0513/84426.png"
defaultCertificateLogoURL = "https://popiart-public-1313913486.cos.ap-guangzhou.myqcloud.com/media/2026/0511/83035.png" defaultCertificateLogoURL = "https://popiart-public-1313913486.cos.ap-guangzhou.myqcloud.com/media/2026/0513/84428.png"
defaultCertificateBucketBaseURL = "https://popi-certificate-1386008232.cos.ap-guangzhou.myqcloud.com" defaultCertificateBucketBaseURL = "https://popi-certificate-1386008232.cos.ap-guangzhou.myqcloud.com"
) )
@ -83,23 +83,33 @@ func GenerateHashCertificate(ctx context.Context, req HashCertificateRequest) (*
if req.Title == "" { if req.Title == "" {
req.Title = "数字作品区块链存证证明" req.Title = "数字作品区块链存证证明"
} }
if req.BackgroundURL == "" && len(req.BackgroundBytes) == 0 {
req.BackgroundURL = defaultCertificateBackgroundURL
}
if req.LogoURL == "" && len(req.LogoBytes) == 0 {
req.LogoURL = defaultCertificateLogoURL
}
if req.BucketBaseURL == "" { if req.BucketBaseURL == "" {
req.BucketBaseURL = defaultCertificateBucketBaseURL req.BucketBaseURL = defaultCertificateBucketBaseURL
} }
background, err := loadCertificateImage(ctx, req.HTTPClient, req.BackgroundURL, req.BackgroundBytes) var err error
backgroundURL := req.BackgroundURL
if backgroundURL == "" && len(req.BackgroundBytes) == 0 {
backgroundURL = defaultCertificateBackgroundURL
}
background, err := loadCertificateImage(ctx, req.HTTPClient, backgroundURL, req.BackgroundBytes)
if err != nil { if err != nil {
return nil, fmt.Errorf("load certificate background: %w", err) if req.BackgroundURL != "" || len(req.BackgroundBytes) > 0 {
return nil, fmt.Errorf("load certificate background: %w", err)
}
background = defaultCertificateBackgroundImage()
}
logoURL := req.LogoURL
if logoURL == "" && len(req.LogoBytes) == 0 {
logoURL = defaultCertificateLogoURL
} }
logo, err := loadCertificateImage(ctx, req.HTTPClient, req.LogoURL, req.LogoBytes) logo, err := loadCertificateImage(ctx, req.HTTPClient, logoURL, req.LogoBytes)
if err != nil { if err != nil {
return nil, fmt.Errorf("load certificate logo: %w", err) if req.LogoURL != "" || len(req.LogoBytes) > 0 {
return nil, fmt.Errorf("load certificate logo: %w", err)
}
logo = defaultCertificateLogoImage()
} }
var workPreview image.Image var workPreview image.Image
@ -266,6 +276,51 @@ func newQRCodeImage(content string, size int) (image.Image, error) {
return qr.Image(size), nil return qr.Image(size), nil
} }
func defaultCertificateBackgroundImage() image.Image {
dc := gg.NewContext(1369, 1920)
dc.SetHexColor("#fffdf8")
dc.Clear()
gradient := gg.NewLinearGradient(0, 0, 1369, 1920)
gradient.AddColorStop(0, mustHexColor("#ffffff"))
gradient.AddColorStop(0.55, mustHexColor("#fff7e7"))
gradient.AddColorStop(1, mustHexColor("#f4e4c5"))
dc.SetFillStyle(gradient)
dc.DrawRectangle(0, 0, 1369, 1920)
dc.Fill()
dc.SetHexColor("#d7b56d")
dc.SetLineWidth(4)
dc.DrawRectangle(60, 60, 1249, 1800)
dc.Stroke()
dc.SetHexColor("#eed594")
dc.SetLineWidth(1)
dc.DrawRectangle(82, 82, 1205, 1756)
dc.Stroke()
return dc.Image()
}
func defaultCertificateLogoImage() image.Image {
dc := gg.NewContext(304, 60)
dc.SetRGBA(0, 0, 0, 0)
dc.Clear()
dc.SetHexColor("#111111")
dc.DrawCircle(32, 30, 24)
dc.Fill()
dc.SetHexColor("#eed594")
dc.DrawCircle(32, 30, 13)
dc.Fill()
dc.SetHexColor("#111111")
dc.DrawCircle(32, 30, 6)
dc.Fill()
dc.SetHexColor("#111111")
dc.DrawRoundedRectangle(74, 16, 170, 28, 14)
dc.Fill()
return dc.Image()
}
func loadCertificateImage(ctx context.Context, client *http.Client, imageURL string, inline []byte) (image.Image, error) { func loadCertificateImage(ctx context.Context, client *http.Client, imageURL string, inline []byte) (image.Image, error) {
var data []byte var data []byte
var err error var err error

2
certificate_flow.go → pkg/zxchainsdk/certificate_flow.go

@ -372,7 +372,7 @@ func UploadCertificatePNGToCOS(ctx context.Context, pngBytes []byte, defaultObje
_, err = client.Object.Put(ctx, objectKey, bytes.NewReader(pngBytes), &cos.ObjectPutOptions{ _, err = client.Object.Put(ctx, objectKey, bytes.NewReader(pngBytes), &cos.ObjectPutOptions{
ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{ ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{
ContentType: "image/png", ContentType: "image/png",
ContentLength: int64(len(pngBytes)), ContentLength: len(pngBytes),
CacheControl: "public, max-age=31536000, immutable", CacheControl: "public, max-age=31536000, immutable",
}, },
}) })

0
client.go → pkg/zxchainsdk/client.go

0
model.go → pkg/zxchainsdk/model.go

52
sdk_client.go → pkg/zxchainsdk/sdk_client.go

@ -50,19 +50,19 @@ func (c *SDKClient) CreateHashAttestation(_ context.Context, req HashAttestation
raw, _ := json.Marshal(resp) raw, _ := json.Marshal(resp)
return &AttestationResult{ return &AttestationResult{
ReceiptID: resp.EvId, // ReceiptID 保存官方 EvSave 返回的 evId。 ReceiptID: resp.EvId,
RequestID: resp.TxId, // RequestID 保存官方 EvSave 返回的 txId。 RequestID: resp.TxId,
Status: "success", // Status 表示本次 SDK 调用成功。 Status: "success",
RawResponse: raw, // RawResponse 保存官方 SDK 原始响应 JSON。 RawResponse: raw,
ExternalRefID: req.BizID, // ExternalRefID 关联业务侧传入的 BizID。 ExternalRefID: req.BizID,
BlockHeight: resp.BlockHeight, // BlockHeight 表示上链区块高度。 BlockHeight: resp.BlockHeight,
TxTime: resp.TxTime, // TxTime 表示官方返回的上链时间。 TxTime: resp.TxTime,
FileName: req.FileName, // FileName 回传业务侧传入的文件名。 FileName: req.FileName,
FileSize: int64(len(data)), // FileSize 表示本次参与 Hash 存证的内容字节数。 FileSize: int64(len(data)),
ContentType: req.ContentType, // ContentType 回传业务侧传入的内容类型。 ContentType: req.ContentType,
StorageURI: req.StorageURI, // StorageURI 回传业务侧保存原始文件的位置。 StorageURI: req.StorageURI,
SM3Hash: sm3Hash, // SM3Hash 表示本次上链内容的 SM3 哈希。 SM3Hash: sm3Hash,
CreatedAt: createdAt, // CreatedAt 表示业务侧传入或 SDK 自动生成的创建时间。 CreatedAt: createdAt,
}, nil }, nil
} }
@ -79,12 +79,12 @@ func (c *SDKClient) QueryHashAttestation(_ context.Context, req HashAttestationQ
raw, _ := json.Marshal(resp) raw, _ := json.Marshal(resp)
return &HashAttestationQueryResult{ return &HashAttestationQueryResult{
EvID: resp.EvId, // EvID 表示查询到的 Hash 存证 evId。 EvID: resp.EvId,
TxID: resp.TxId, // TxID 表示查询到的链上交易 txId。 TxID: resp.TxId,
BlockHeight: resp.BlockHeight, // BlockHeight 表示查询到的上链区块高度。 BlockHeight: resp.BlockHeight,
TxTime: resp.TxTime, // TxTime 表示查询到的上链时间。 TxTime: resp.TxTime,
ExtendInfo: resp.ExtendInfo, // ExtendInfo 表示存证时传入的业务场景信息。 ExtendInfo: resp.ExtendInfo,
RawResponse: raw, // RawResponse 保存官方 SDK 原始响应 JSON。 RawResponse: raw,
}, nil }, nil
} }
@ -103,11 +103,11 @@ func (c *SDKClient) CreateKVAttestation(_ context.Context, req KVAttestationRequ
raw, _ := json.Marshal(resp) raw, _ := json.Marshal(resp)
return &AttestationResult{ return &AttestationResult{
ReceiptID: resp.TxId, // ReceiptID 保存 KV 查询结果中的 txId。 ReceiptID: resp.TxId,
RequestID: resp.TxId, // RequestID 保存 KV 查询结果中的 txId。 RequestID: resp.TxId,
Status: "success", // Status 表示本次 SDK 调用成功。 Status: "success",
RawResponse: raw, // RawResponse 保存官方 SDK 原始响应 JSON。 RawResponse: raw,
ExternalRefID: resp.KvKey, // ExternalRefID 保存链上的 kvKey。 ExternalRefID: resp.KvKey,
}, nil }, nil
} }
@ -123,7 +123,7 @@ func (c *SDKClient) GetHashCert(_ context.Context, evID string) (*HashCertResult
} }
return &HashCertResult{ return &HashCertResult{
EvID: evID, // EvID 表示 Hash 存证回执中的 evId。 EvID: evID,
CertURL: certURL, // CertURL 表示官方证书访问地址。 CertURL: certURL,
}, nil }, nil
} }
Loading…
Cancel
Save