66 lines
1.4 KiB
Go
66 lines
1.4 KiB
Go
// Package model 提供 Orbit 各模块共用且不绑定存储实现的基础类型。
|
||
// 服务端模型不直接作为公开 SDK 协议。
|
||
package model
|
||
|
||
import (
|
||
"crypto/rand"
|
||
"database/sql/driver"
|
||
"encoding/hex"
|
||
"encoding/json"
|
||
"errors"
|
||
"fmt"
|
||
)
|
||
|
||
// ID 是 128 位随机标识,对外使用小写十六进制,MySQL 使用 BINARY(16)。
|
||
// 标识只用于定位资源,不能作为访问凭据。
|
||
type ID string
|
||
|
||
func NewID() (ID, error) {
|
||
var b [16]byte
|
||
if _, err := rand.Read(b[:]); err != nil {
|
||
return "", err
|
||
}
|
||
return ID(hex.EncodeToString(b[:])), nil
|
||
}
|
||
|
||
func (id ID) Validate() error {
|
||
if len(id) != 32 {
|
||
return errors.New("id must contain 32 lowercase hexadecimal characters")
|
||
}
|
||
for _, c := range id {
|
||
if !(c >= '0' && c <= '9' || c >= 'a' && c <= 'f') {
|
||
return errors.New("id must contain lowercase hexadecimal characters")
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (id ID) Value() (driver.Value, error) {
|
||
if err := id.Validate(); err != nil {
|
||
return nil, err
|
||
}
|
||
return hex.DecodeString(string(id))
|
||
}
|
||
|
||
func (id *ID) Scan(src any) error {
|
||
b, ok := src.([]byte)
|
||
if !ok || len(b) != 16 {
|
||
return fmt.Errorf("id: expected BINARY(16), got %T", src)
|
||
}
|
||
*id = ID(hex.EncodeToString(b))
|
||
return nil
|
||
}
|
||
|
||
func (id *ID) UnmarshalJSON(b []byte) error {
|
||
var s string
|
||
if err := json.Unmarshal(b, &s); err != nil {
|
||
return err
|
||
}
|
||
candidate := ID(s)
|
||
if err := candidate.Validate(); err != nil {
|
||
return err
|
||
}
|
||
*id = candidate
|
||
return nil
|
||
}
|