提供基础框架

This commit is contained in:
JeshuaRen 2025-03-31 15:38:19 +08:00
parent 654143f5a6
commit 8f1e814ef6
43 changed files with 3678 additions and 4 deletions

41
client/go.mod Normal file
View File

@ -0,0 +1,41 @@
module gitlink.org.cn/JointCloud/pcm-participant-client
go 1.23.0
replace gitlink.org.cn/JointCloud/pcm-participant-common v0.0.0 => ../common
require (
github.com/gin-gonic/gin v1.10.0
gitlink.org.cn/JointCloud/pcm-participant-common v0.0.0
)
require (
github.com/antonfisher/nested-logrus-formatter v1.3.1 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

102
client/go.sum Normal file
View File

@ -0,0 +1,102 @@
github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ=
github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

@ -0,0 +1,22 @@
package http
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data any `json:"data"`
}
func OK(data any) Response {
return Response{
Code: 200,
Message: "",
Data: data,
}
}
func Failed(code int, msg string) Response {
return Response{
Code: code,
Message: msg,
}
}

View File

@ -0,0 +1,36 @@
package http
import (
"github.com/gin-gonic/gin"
errorcode "gitlink.org.cn/JointCloud/pcm-participant-common/consts"
"gitlink.org.cn/JointCloud/pcm-participant-common/pkgs/logger"
"net/http"
)
type PCMService struct {
*Server
}
func (s *Server) PCMSvc() *PCMService {
return &PCMService{
Server: s,
}
}
type SubmitReq struct {
}
func (s *PCMService) Submit(ctx *gin.Context) {
log := logger.WithField("HTTP", "JobSet.LocalFileUploaded")
var req SubmitReq
if err := ctx.ShouldBindJSON(&req); err != nil {
log.Warnf("binding body: %s", err.Error())
ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadRequest, "missing argument or invalid argument"))
return
}
s.svc.PCMSvc()
ctx.JSON(http.StatusOK, OK(nil))
}

View File

@ -0,0 +1,42 @@
package http
import (
"github.com/gin-gonic/gin"
"gitlink.org.cn/JointCloud/pcm-participant-client/internal/services"
"gitlink.org.cn/JointCloud/pcm-participant-common/pkgs/logger"
)
type Server struct {
engine *gin.Engine
listenAddr string
svc *services.Service
}
func NewServer(listenAddr string, svc *services.Service) (*Server, error) {
engine := gin.New()
return &Server{
engine: engine,
listenAddr: listenAddr,
svc: svc,
}, nil
}
func (s *Server) Serve() error {
s.initRouters()
logger.Infof("start serving http at: %s", s.listenAddr)
err := s.engine.Run(s.listenAddr)
if err != nil {
logger.Infof("http stopped with error: %s", err.Error())
return err
}
logger.Infof("http stopped")
return nil
}
func (s *Server) initRouters() {
s.engine.POST("/pcm/submit", s.PCMSvc().Submit)
}

24
client/internal/main.go Normal file
View File

@ -0,0 +1,24 @@
package main
import (
"gitlink.org.cn/JointCloud/pcm-participant-client/internal/http"
"gitlink.org.cn/JointCloud/pcm-participant-client/internal/services"
"gitlink.org.cn/JointCloud/pcm-participant-common/pkgs/logger"
"os"
)
func main() {
svc := services.NewService()
httpSvr, err := http.NewServer("7895", svc)
if err != nil {
logger.Errorf(err.Error())
os.Exit(1)
}
err = httpSvr.Serve()
if err != nil {
logger.Errorf(err.Error())
os.Exit(1)
}
}

View File

@ -0,0 +1,13 @@
package services
type PCMService struct {
*Service
}
func (svc *Service) PCMSvc() *PCMService {
return &PCMService{Service: svc}
}
func (svc *PCMService) Submit() {
}

View File

@ -0,0 +1,8 @@
package services
type Service struct {
}
func NewService() *Service {
return &Service{}
}

View File

@ -0,0 +1,12 @@
package errorcode
const (
OK = 200
Unauthorized = 401
Forbidden = 403
NotFound = 404
InternalError = 500
BadRequest = 400
UnknownError = 999
Unknown = 999
)

View File

@ -1 +0,0 @@
package common

View File

@ -0,0 +1,30 @@
package model
import (
"gitlink.org.cn/JointCloud/pcm-participant-common/pkgs/types"
"gitlink.org.cn/JointCloud/pcm-participant-common/utils/serder"
)
type SubmitJobInfo interface {
GetLocalJobID() string
}
var JobInfoTypeUnion = types.NewTypeUnion[SubmitJobInfo](
(*NormalJobInfo)(nil),
)
var _ = serder.UseTypeUnionInternallyTagged(&JobInfoTypeUnion, "type")
type JobInfoBase struct {
LocalJobID string `json:"localJobID"`
}
func (i *JobInfoBase) GetLocalJobID() string {
return i.LocalJobID
}
type NormalJobInfo struct {
serder.Metadata `union:"Normal"`
JobInfoBase
Type string `json:"type"`
}

7
common/define/pcm.go Normal file
View File

@ -0,0 +1,7 @@
package define
import definemodel "gitlink.org.cn/JointCloud/pcm-participant-common/define/model"
type PCMProvider interface {
Submit(info definemodel.SubmitJobInfo) (string, string, error)
}

21
common/go.mod Normal file
View File

@ -0,0 +1,21 @@
module gitlink.org.cn/JointCloud/pcm-participant-common
go 1.23.0
require (
github.com/antonfisher/nested-logrus-formatter v1.3.1
github.com/json-iterator/go v1.1.12
github.com/mitchellh/mapstructure v1.5.0
github.com/modern-go/reflect2 v1.0.2
github.com/sirupsen/logrus v1.9.3
github.com/smartystreets/goconvey v1.8.1
github.com/zyedidia/generic v1.2.1
)
require (
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/smarty/assertions v1.15.0 // indirect
golang.org/x/sys v0.6.0 // indirect
)

38
common/go.sum Normal file
View File

@ -0,0 +1,38 @@
github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ=
github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/zyedidia/generic v1.2.1 h1:Zv5KS/N2m0XZZiuLS82qheRG4X1o5gsWreGb0hR7XDc=
github.com/zyedidia/generic v1.2.1/go.mod h1:ly2RBz4mnz1yeuVbQA/VFwGjK3mnHGRj1JuoG336Bis=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -0,0 +1,8 @@
package logger
type Config struct {
Output string `json:"output"` // 输出日志的方式。file输出到文件stdout输出到标准输出
OutputFileName string `json:"outputFileName"` // 输出日志的文件名只在Output字段为file时有意义
OutputDirectory string `json:"outputDirectory"` // 输出日志的目录只在Output字段为file时有意义
Level string `json:"level"`
}

View File

@ -0,0 +1,163 @@
package logger
import (
"fmt"
"os"
"path/filepath"
"strings"
nested "github.com/antonfisher/nested-logrus-formatter"
"github.com/sirupsen/logrus"
"gitlink.org.cn/JointCloud/pcm-participant-common/utils/reflect2"
)
// Std 是一个输出日志到标准输出的Logger适用于没有设计好日志输出方案时的临时使用。
var Std Logger
// init 初始化包设置日志格式为不带颜色的Nested格式日志级别为Debug输出到标准输出。
func init() {
logger := logrus.New()
logger.SetFormatter(&nested.Formatter{
TimestampFormat: "2006-01-02 15:04:05",
NoColors: true,
NoFieldsColors: true,
})
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(os.Stdout)
Std = &logrusLogger{entry: logger.WithField("TODO", "")}
}
// Init 初始化全局默认的日志器,根据配置设置日志级别和输出位置。
//
// 参数:
//
// cfg *Config: 日志配置项,包括日志级别和输出位置等。
//
// 返回值:
//
// error: 初始化过程中的任何错误。
func Init(cfg *Config) error {
logrus.SetFormatter(&nested.Formatter{
TimestampFormat: "2006-01-02 15:04:05",
NoColors: true,
NoFieldsColors: true,
})
// 设置日志级别
level, ok := loggerLevels[strings.ToUpper(cfg.Level)]
if !ok {
return fmt.Errorf("invalid log level: %s", cfg.Level)
}
logrus.SetLevel(level)
// 设置日志输出位置
output := strings.ToUpper(cfg.Output)
if output == OUTPUT_FILE {
logFilePath := filepath.Join(cfg.OutputDirectory, cfg.OutputFileName+".log")
// 创建日志文件所在的目录
if err := os.MkdirAll(cfg.OutputDirectory, 0755); err != nil {
return err
}
// 打开或创建日志文件
file, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0755)
if err != nil {
return err
}
logrus.SetOutput(file)
} else if output == OUTPUT_STDOUT {
logrus.SetOutput(os.Stdout)
} else {
logrus.SetOutput(os.Stdout)
logrus.Warnf("unsupported output: %s, will output to stdout", output)
}
return nil
}
// 下面是日志记录的方法,它们分别对应不同的日志级别和格式。
// 这些方法最终都会调用logrus对应的方法来记录日志。
func Debug(args ...interface{}) {
logrus.Debug(args...)
}
func Debugf(format string, args ...interface{}) {
logrus.Debugf(format, args...)
}
func Info(args ...interface{}) {
logrus.Info(args...)
}
func Infof(format string, args ...interface{}) {
logrus.Infof(format, args...)
}
func Warn(args ...interface{}) {
logrus.Warn(args...)
}
func Warnf(format string, args ...interface{}) {
logrus.Warnf(format, args...)
}
func Error(args ...interface{}) {
logrus.Error(args...)
}
func Errorf(format string, args ...interface{}) {
logrus.Errorf(format, args...)
}
func Fatal(args ...interface{}) {
logrus.Fatal(args...)
}
func Fatalf(format string, args ...interface{}) {
logrus.Fatalf(format, args...)
}
func Panic(args ...interface{}) {
logrus.Panic(args...)
}
func Panicf(format string, args ...interface{}) {
logrus.Panicf(format, args...)
}
// WithField 创建并返回一个新的Logger该Logger在记录日志时会包含额外的字段。
//
// 参数:
//
// key string: 字段键。
// val any: 字段值。
//
// 返回值:
//
// Logger: 包含指定字段的Logger。
func WithField(key string, val any) Logger {
return &logrusLogger{
entry: logrus.WithField(key, val),
}
}
// WithType 创建并返回一个新的Logger该Logger在记录日志时会包含类型的字段。
//
// 参数:
//
// key string: 字段键。
//
// 返回值:
//
// Logger: 包含指定类型字段的Logger。
func WithType[T any](key string) Logger {
return &logrusLogger{
entry: logrus.WithField(key, reflect2.TypeOf[T]().Name()),
}
}

View File

@ -0,0 +1,54 @@
package logger
import (
"reflect"
"github.com/sirupsen/logrus"
)
const (
TRACE_LEVEL = "TRACE"
DEBUG_LEVEL = "DEBUG"
INFO_LEVEL = "INFO"
WARN_LEVEL = "WARN"
ERROR_LEVEL = "ERROR"
FATAL_LEVEL = "FATAL"
PANIC_LEVEL = "PANIC"
OUTPUT_FILE = "FILE"
OUTPUT_STDOUT = "STDOUT"
)
var loggerLevels = map[string]logrus.Level{
TRACE_LEVEL: logrus.TraceLevel,
DEBUG_LEVEL: logrus.DebugLevel,
INFO_LEVEL: logrus.InfoLevel,
WARN_LEVEL: logrus.WarnLevel,
ERROR_LEVEL: logrus.ErrorLevel,
FATAL_LEVEL: logrus.FatalLevel,
PANIC_LEVEL: logrus.PanicLevel,
}
type Logger interface {
Debug(args ...interface{})
Debugf(format string, args ...interface{})
Info(args ...interface{})
Infof(format string, args ...interface{})
Warn(args ...interface{})
Warnf(format string, args ...interface{})
Error(args ...interface{})
Errorf(format string, args ...interface{})
Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
Panic(args ...interface{})
Panicf(format string, args ...interface{})
WithField(key string, val any) Logger
WithType(key string, typ reflect.Type) Logger
}

View File

@ -0,0 +1,55 @@
package logger
import (
"fmt"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_FormatStruct(t *testing.T) {
type Struct2 struct {
Int int
}
type Struct struct {
Arr []int
NilArr []int
FixedArr [5]int
St2 Struct2
St2Ptr *Struct2
NilSt2Ptr *Struct2
Struct2
}
st := Struct{
Arr: []int{1, 2, 3, 4},
NilArr: nil,
FixedArr: [5]int{1, 2, 3, 4, 5},
St2: Struct2{
Int: 123,
},
St2Ptr: &Struct2{
Int: 456,
},
NilSt2Ptr: nil,
Struct2: Struct2{
Int: 789,
},
}
fmtedStr := "len(Arr): 4, NilArr: <nil>, len(FixedArr): 5, St2: <Struct2>, St2Ptr: &<Struct2>, NilSt2Ptr: <nil>, Int: 789"
Convey("基本格式", t, func() {
So(fmt.Sprintf("%v", FormatStruct(st)), ShouldEqual, fmtedStr)
})
Convey("指针", t, func() {
So(fmt.Sprintf("%v", FormatStruct(&st)), ShouldEqual, fmtedStr)
})
Convey("interface", t, func() {
var ift any = st
So(fmt.Sprintf("%v", FormatStruct(ift)), ShouldEqual, fmtedStr)
})
}

View File

@ -0,0 +1,65 @@
package logger
import (
"reflect"
"github.com/sirupsen/logrus"
)
type logrusLogger struct {
entry *logrus.Entry
}
func (l *logrusLogger) Debug(args ...interface{}) {
l.entry.Debug(args...)
}
func (l *logrusLogger) Debugf(format string, args ...interface{}) {
l.entry.Debugf(format, args...)
}
func (l *logrusLogger) Info(args ...interface{}) {
l.entry.Info(args...)
}
func (l *logrusLogger) Infof(format string, args ...interface{}) {
l.entry.Infof(format, args...)
}
func (l *logrusLogger) Warn(args ...interface{}) {
l.entry.Warn(args...)
}
func (l *logrusLogger) Warnf(format string, args ...interface{}) {
l.entry.Warnf(format, args...)
}
func (l *logrusLogger) Error(args ...interface{}) {
l.entry.Error(args...)
}
func (l *logrusLogger) Errorf(format string, args ...interface{}) {
l.entry.Errorf(format, args...)
}
func (l *logrusLogger) Fatal(args ...interface{}) {
l.entry.Fatal(args...)
}
func (l *logrusLogger) Fatalf(format string, args ...interface{}) {
l.entry.Fatalf(format, args...)
}
func (l *logrusLogger) Panic(args ...interface{}) {
l.entry.Panic(args...)
}
func (l *logrusLogger) Panicf(format string, args ...interface{}) {
l.entry.Panicf(format, args...)
}
func (l *logrusLogger) WithField(key string, val any) Logger {
return &logrusLogger{
entry: l.entry.WithField(key, val),
}
}
func (l *logrusLogger) WithType(key string, typ reflect.Type) Logger {
return &logrusLogger{
entry: l.entry.WithField(key, typ.Name()),
}
}

101
common/pkgs/logger/utils.go Normal file
View File

@ -0,0 +1,101 @@
package logger
import (
"fmt"
"reflect"
"strings"
)
type structFormatter struct {
val any
}
func (f *structFormatter) String() string {
realVal := reflect.ValueOf(f.val)
for {
kind := realVal.Type().Kind()
if kind == reflect.Struct {
sb := strings.Builder{}
f.structString(realVal, &sb)
return sb.String()
}
if kind == reflect.Pointer {
realVal = realVal.Elem()
continue
}
return fmt.Sprintf("%v", f.val)
}
}
func (f *structFormatter) structString(val reflect.Value, strBuilder *strings.Builder) {
typ := val.Type()
for i := 0; i < val.NumField(); i++ {
fieldInfo := typ.Field(i)
fieldValue := val.Field(i)
fieldType := fieldInfo.Type
fieldKind := fieldType.Kind()
if i > 0 {
strBuilder.WriteString(", ")
}
switch fieldKind {
case reflect.Slice:
if fieldValue.IsNil() {
strBuilder.WriteString(fieldInfo.Name)
strBuilder.WriteString(": <nil>")
} else {
strBuilder.WriteString("len(")
strBuilder.WriteString(fieldInfo.Name)
strBuilder.WriteString("): ")
strBuilder.WriteString(fmt.Sprintf("%d", fieldValue.Len()))
}
case reflect.Array:
strBuilder.WriteString("len(")
strBuilder.WriteString(fieldInfo.Name)
strBuilder.WriteString("): ")
strBuilder.WriteString(fmt.Sprintf("%d", fieldValue.Len()))
case reflect.Struct:
if fieldInfo.Anonymous {
f.structString(fieldValue, strBuilder)
} else {
strBuilder.WriteString(fieldInfo.Name)
strBuilder.WriteString(": <")
strBuilder.WriteString(fieldType.Name())
strBuilder.WriteString(">")
}
case reflect.Pointer:
strBuilder.WriteString(fieldInfo.Name)
if fieldValue.IsNil() {
strBuilder.WriteString(": <nil>")
} else {
strBuilder.WriteString(": &<")
strBuilder.WriteString(fieldType.Elem().Name())
strBuilder.WriteString(">")
}
default:
strBuilder.WriteString(fieldInfo.Name)
strBuilder.WriteString(": ")
strBuilder.WriteString(fmt.Sprintf("%v", fieldValue))
}
}
}
// FormatStruct 输出结构体的内容。
// 1. 数组类型只会输出长度
// 2. 内部的结构体的内容不会再输出包括embeded字段
func FormatStruct(val any) any {
return &structFormatter{
val: val,
}
}

View File

@ -0,0 +1,5 @@
package types
func Ref[T any](val T) *T {
return &val
}

View File

@ -0,0 +1,62 @@
package types
import (
"fmt"
"reflect"
"gitlink.org.cn/JointCloud/pcm-participant-common/utils/reflect2"
)
type AnyTypeUnion struct {
// 这个集合的类型
UnionType reflect2.Type
// 集合中包含的类型即遇到UnionType类型的值时它内部的实际类型的范围
ElementTypes []reflect2.Type
}
func (u *AnyTypeUnion) Include(typ reflect2.Type) bool {
for _, t := range u.ElementTypes {
if t == typ {
return true
}
}
return false
}
func (u *AnyTypeUnion) Add(typ reflect2.Type) error {
if !typ.AssignableTo(u.UnionType) {
return fmt.Errorf("type is not assignable to union type")
}
u.ElementTypes = append(u.ElementTypes, typ)
return nil
}
// 描述一个类型集合
type TypeUnion[T any] struct {
AnyTypeUnion
}
func (u *TypeUnion[T]) AddT(nilValue T) {
u.ElementTypes = append(u.ElementTypes, reflect.TypeOf(nilValue))
}
func (u *TypeUnion[T]) ToAny() *AnyTypeUnion {
return &u.AnyTypeUnion
}
// 创建一个TypeUnion。泛型参数为Union的类型形参为Union中包含的类型的一个实例无实际用途仅用于获取类型。
func NewTypeUnion[TU any](eleValues ...TU) TypeUnion[TU] {
var eleTypes []reflect.Type
for _, v := range eleValues {
eleTypes = append(eleTypes, reflect.TypeOf(v))
}
return TypeUnion[TU]{
AnyTypeUnion{
UnionType: reflect2.TypeOf[TU](),
ElementTypes: eleTypes,
},
}
}

View File

@ -0,0 +1 @@
package register

View File

@ -0,0 +1,24 @@
package reflect2
import "reflect"
type Type = reflect.Type
// TypeOfValue 获得实际值的类型
func TypeOfValue(val any) reflect.Type {
return reflect.TypeOf(val)
}
// TypeOf 获得泛型的类型
func TypeOf[T any]() reflect.Type {
return reflect.TypeOf([0]T{}).Elem()
}
// ElemTypeOf 获得泛型的类型。适用于数组、指针类型
func ElemTypeOf[T any]() reflect.Type {
return reflect.TypeOf([0]T{}).Elem().Elem()
}
func TypeNameOf[T any]() string {
return TypeOf[T]().Name()
}

View File

@ -0,0 +1,145 @@
package serder
import (
"reflect"
mp "github.com/mitchellh/mapstructure"
"gitlink.org.cn/JointCloud/pcm-participant-common/utils/reflect2"
)
type Converter func(from reflect.Value, to reflect.Value) (interface{}, error)
type AnyToAnyOption struct {
NoFromAny bool // 不判断目的字段是否实现了FromAny接口
NoToAny bool // 不判断源字段是否实现了ToAny接口
Converters []Converter // 字段类型转换函数
// 当目的类型为map[string]any是否要递归的将源类型的每一个字段都变成map[string]any。
// 注:字段的类型(而不是实际值的类型)必须为结构体或者结构体指针。
RecursiveStructToMap bool
}
type FromAny interface {
FromAny(val any) (ok bool, err error)
}
type ToAny interface {
ToAny(typ reflect.Type) (val any, ok bool, err error)
}
// AnyToAny 相同结构的任意类型对象之间的转换
func AnyToAny(src any, dst any, opts ...AnyToAnyOption) error {
var opt AnyToAnyOption
if len(opts) > 0 {
opt = opts[0]
}
var hooks []mp.DecodeHookFunc
if !opt.NoToAny {
hooks = append(hooks, toAny)
}
if !opt.NoFromAny {
hooks = append(hooks, fromAny)
}
for _, c := range opt.Converters {
hooks = append(hooks, c)
}
if opt.RecursiveStructToMap {
hooks = append(hooks, mp.RecursiveStructToMapHookFunc())
}
config := &mp.DecoderConfig{
TagName: "json",
Squash: true,
WeaklyTypedInput: true,
Result: dst,
DecodeHook: mp.ComposeDecodeHookFunc(hooks...),
}
decoder, err := mp.NewDecoder(config)
if err != nil {
return err
}
return decoder.Decode(src)
}
// fromAny 如果目的字段实现的FromAny接口那么通过此接口实现字段类型转换
func fromAny(srcType reflect.Type, targetType reflect.Type, data interface{}) (interface{}, error) {
if reflect2.TypeOfValue(data) == targetType {
return data, nil
}
if targetType.Implements(reflect2.TypeOf[FromAny]()) {
// 非pointer receiver的FromAny没有意义因为修改不了receiver的内容所以这里只支持指针类型
if targetType.Kind() == reflect.Pointer {
val := reflect.New(targetType.Elem())
anyIf := val.Interface().(FromAny)
ok, err := anyIf.FromAny(data)
if err != nil {
return nil, err
}
if !ok {
return data, nil
}
return val.Interface(), nil
}
} else if reflect.PointerTo(targetType).Implements(reflect2.TypeOf[FromAny]()) {
val := reflect.New(targetType)
anyIf := val.Interface().(FromAny)
ok, err := anyIf.FromAny(data)
if err != nil {
return nil, err
}
if !ok {
return data, nil
}
return val.Interface(), nil
}
return data, nil
}
// 如果源字段实现了ToAny接口那么通过此接口实现字段类型转换
func toAny(srcType reflect.Type, targetType reflect.Type, data interface{}) (interface{}, error) {
dataType := reflect2.TypeOfValue(data)
if dataType == targetType {
return data, nil
}
if dataType.Implements(reflect2.TypeOf[ToAny]()) {
anyIf := data.(ToAny)
dstVal, ok, err := anyIf.ToAny(targetType)
if err != nil {
return nil, err
}
if !ok {
return data, nil
}
return dstVal, nil
} else if reflect.PointerTo(dataType).Implements(reflect2.TypeOf[ToAny]()) {
dataVal := reflect.ValueOf(data)
dataPtrVal := reflect.New(dataType)
dataPtrVal.Elem().Set(dataVal)
anyIf := dataPtrVal.Interface().(ToAny)
dstVal, ok, err := anyIf.ToAny(targetType)
if err != nil {
return nil, err
}
if !ok {
return data, nil
}
return dstVal, nil
}
return data, nil
}

View File

@ -0,0 +1,72 @@
package json
import (
"reflect"
jsoniter "github.com/json-iterator/go"
"gitlink.org.cn/JointCloud/pcm-participant-common/pkgs/types"
)
type Config struct {
unionHandler *UnionHandler
exts []jsoniter.Extension
}
func New() *Config {
return &Config{
unionHandler: &UnionHandler{
internallyTagged: make(map[reflect.Type]*anyTypeUnionInternallyTagged),
externallyTagged: make(map[reflect.Type]*anyTypeUnionExternallyTagged),
},
}
}
func (c *Config) UseUnionInternallyTagged(u *types.AnyTypeUnion, tagField string) *Config {
iu := &anyTypeUnionInternallyTagged{
Union: u,
TagField: tagField,
TagToType: make(map[string]reflect.Type),
}
for _, eleType := range u.ElementTypes {
iu.Add(eleType)
}
c.unionHandler.internallyTagged[u.UnionType] = iu
return c
}
func (c *Config) UseUnionExternallyTagged(u *types.AnyTypeUnion) *Config {
eu := &anyTypeUnionExternallyTagged{
Union: u,
TypeNameToType: make(map[string]reflect.Type),
}
for _, eleType := range u.ElementTypes {
eu.Add(eleType)
}
c.unionHandler.externallyTagged[u.UnionType] = eu
return c
}
func (c *Config) UseExtension(ext jsoniter.Extension) *Config {
c.exts = append(c.exts, ext)
return c
}
func (c *Config) Build() Serder {
cfg := jsoniter.Config{}
api := cfg.Froze()
api.RegisterExtension(c.unionHandler)
for _, ext := range c.exts {
api.RegisterExtension(ext)
}
return Serder{
cfg: *c,
api: api,
}
}

View File

@ -0,0 +1,29 @@
package json
import (
"bytes"
jsoniter "github.com/json-iterator/go"
)
type Serder struct {
cfg Config
api jsoniter.API
}
func (s *Serder) Encode(obj any) ([]byte, error) {
buf := new(bytes.Buffer)
enc := s.api.NewEncoder(buf)
err := enc.Encode(obj)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (s *Serder) Decode(data []byte, obj any) error {
dec := s.api.NewDecoder(bytes.NewReader(data))
return dec.Decode(&obj)
}

View File

@ -0,0 +1,318 @@
package json
import (
"fmt"
"reflect"
"unsafe"
jsoniter "github.com/json-iterator/go"
"github.com/modern-go/reflect2"
"gitlink.org.cn/JointCloud/pcm-participant-common/pkgs/types"
stypes "gitlink.org.cn/JointCloud/pcm-participant-common/utils/serder/types"
ref2 "gitlink.org.cn/JointCloud/pcm-participant-common/utils/reflect2"
)
type anyTypeUnionExternallyTagged struct {
Union *types.AnyTypeUnion
TypeNameToType map[string]reflect.Type
}
func (u *anyTypeUnionExternallyTagged) Add(typ reflect.Type) error {
err := u.Union.Add(typ)
if err != nil {
return nil
}
u.TypeNameToType[makeDerefFullTypeName(typ)] = typ
return nil
}
type TypeUnionExternallyTagged[T any] struct {
anyTypeUnionExternallyTagged
TUnion *types.TypeUnion[T]
}
func (u *TypeUnionExternallyTagged[T]) AddT(nilValue T) error {
u.Add(reflect.TypeOf(nilValue))
return nil
}
type anyTypeUnionInternallyTagged struct {
Union *types.AnyTypeUnion
TagField string
TagToType map[string]reflect.Type
}
func (u *anyTypeUnionInternallyTagged) Add(typ reflect.Type) error {
err := u.Union.Add(typ)
if err != nil {
return nil
}
// 解引用直到得到结构体类型
structType := typ
for structType.Kind() == reflect.Pointer {
structType = structType.Elem()
}
// 要求内嵌Metadata结构体那么结构体中的字段名就会是Metadata
field, ok := structType.FieldByName(ref2.TypeNameOf[stypes.Metadata]())
if !ok {
u.TagToType[makeDerefFullTypeName(structType)] = typ
return nil
}
// 为防同名检查类型是不是也是Metadata
if field.Type != ref2.TypeOf[stypes.Metadata]() {
u.TagToType[makeDerefFullTypeName(structType)] = typ
return nil
}
tag := field.Tag.Get("union")
if tag == "" {
u.TagToType[makeDerefFullTypeName(structType)] = typ
return nil
}
u.TagToType[tag] = typ
return nil
}
type TypeUnionInternallyTagged[T any] struct {
anyTypeUnionInternallyTagged
TUnion *types.TypeUnion[T]
}
func (u *TypeUnionInternallyTagged[T]) AddT(nilValue T) error {
u.Add(reflect.TypeOf(nilValue))
return nil
}
type UnionHandler struct {
internallyTagged map[reflect.Type]*anyTypeUnionInternallyTagged
externallyTagged map[reflect.Type]*anyTypeUnionExternallyTagged
}
func (h *UnionHandler) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
}
func (h *UnionHandler) CreateMapKeyDecoder(typ reflect2.Type) jsoniter.ValDecoder {
return nil
}
func (h *UnionHandler) CreateMapKeyEncoder(typ reflect2.Type) jsoniter.ValEncoder {
return nil
}
func (h *UnionHandler) CreateDecoder(typ reflect2.Type) jsoniter.ValDecoder {
typ1 := typ.Type1()
if it, ok := h.internallyTagged[typ1]; ok {
return &InternallyTaggedDecoder{
union: it,
}
}
if et, ok := h.externallyTagged[typ1]; ok {
return &ExternallyTaggedDecoder{
union: et,
}
}
return nil
}
func (h *UnionHandler) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder {
typ1 := typ.Type1()
if it, ok := h.internallyTagged[typ1]; ok {
return &InternallyTaggedEncoder{
union: it,
}
}
if et, ok := h.externallyTagged[typ1]; ok {
return &ExternallyTaggedEncoder{
union: et,
}
}
return nil
}
func (h *UnionHandler) DecorateDecoder(typ reflect2.Type, decoder jsoniter.ValDecoder) jsoniter.ValDecoder {
return decoder
}
func (h *UnionHandler) DecorateEncoder(typ reflect2.Type, encoder jsoniter.ValEncoder) jsoniter.ValEncoder {
return encoder
}
// 以下Encoder/Decoder都是在传入类型/目标类型是TypeUnion的基类UnionType时使用
type InternallyTaggedEncoder struct {
union *anyTypeUnionInternallyTagged
}
func (e *InternallyTaggedEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return false
}
func (e *InternallyTaggedEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
var val any
if e.union.Union.UnionType.NumMethod() == 0 {
// 无方法的interface底层都是eface结构体所以可以直接转*any
val = *(*any)(ptr)
} else {
// 有方法的interface底层都是iface结构体可以将其转成eface转换后不损失类型信息
val = reflect2.IFaceToEFace(ptr)
}
// 可以考虑检查一下Type字段有没有赋值没有赋值则将其赋值为union Tag指定的值
stream.WriteVal(val)
}
type InternallyTaggedDecoder struct {
union *anyTypeUnionInternallyTagged
}
func (e *InternallyTaggedDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
nextTokenKind := iter.WhatIsNext()
if nextTokenKind == jsoniter.NilValue {
iter.Skip()
return
}
raw := iter.ReadAny()
if raw.LastError() != nil {
iter.ReportError("decode TaggedUnionType", "getting object raw:"+raw.LastError().Error())
return
}
tagField := raw.Get(e.union.TagField)
if tagField.LastError() != nil {
iter.ReportError("decode TaggedUnionType", "getting type tag field:"+tagField.LastError().Error())
return
}
typeTag := tagField.ToString()
if typeTag == "" {
iter.ReportError("decode TaggedUnionType", "type tag is empty")
return
}
typ, ok := e.union.TagToType[typeTag]
if !ok {
iter.ReportError("decode TaggedUnionType", fmt.Sprintf("unknow type tag %s in union %s", typeTag, e.union.Union.UnionType.Name()))
return
}
// 如果目标类型已经是个指针类型*T那么在New的时候就需要使用T
// 否则New出来的是会是**T这将导致后续的反序列化出问题
if typ.Kind() == reflect.Pointer {
val := reflect.New(typ.Elem())
raw.ToVal(val.Interface())
retVal := reflect.NewAt(e.union.Union.UnionType, ptr)
retVal.Elem().Set(val)
} else {
val := reflect.New(typ)
raw.ToVal(val.Interface())
retVal := reflect.NewAt(e.union.Union.UnionType, ptr)
retVal.Elem().Set(val.Elem())
}
}
type ExternallyTaggedEncoder struct {
union *anyTypeUnionExternallyTagged
}
func (e *ExternallyTaggedEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return false
}
func (e *ExternallyTaggedEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
var val any
if e.union.Union.UnionType.NumMethod() == 0 {
// 无方法的interface底层都是eface结构体所以可以直接转*any
val = *(*any)(ptr)
} else {
// 有方法的interface底层都是iface结构体可以将其转成eface转换后不损失类型信息
val = reflect2.IFaceToEFace(ptr)
}
if val == nil {
stream.WriteNil()
return
}
stream.WriteObjectStart()
valType := ref2.TypeOfValue(val)
if !e.union.Union.Include(valType) {
stream.Error = fmt.Errorf("type %v is not in union %v", valType, e.union.Union.UnionType)
return
}
stream.WriteObjectField(makeDerefFullTypeName(valType))
stream.WriteVal(val)
stream.WriteObjectEnd()
}
type ExternallyTaggedDecoder struct {
union *anyTypeUnionExternallyTagged
}
func (e *ExternallyTaggedDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
nextTkType := iter.WhatIsNext()
if nextTkType == jsoniter.NilValue {
iter.Skip()
return
}
if nextTkType != jsoniter.ObjectValue {
iter.ReportError("decode UnionType", fmt.Sprintf("unknow next token type %v", nextTkType))
return
}
typeStr := iter.ReadObject()
if typeStr == "" {
iter.ReportError("decode UnionType", "type string is empty")
}
typ, ok := e.union.TypeNameToType[typeStr]
if !ok {
iter.ReportError("decode UnionType", fmt.Sprintf("unknow type string %s in union %v", typeStr, e.union.Union.UnionType))
return
}
// 如果目标类型已经是个指针类型*T那么在New的时候就需要使用T
// 否则New出来的是会是**T这将导致后续的反序列化出问题
if typ.Kind() == reflect.Pointer {
val := reflect.New(typ.Elem())
iter.ReadVal(val.Interface())
retVal := reflect.NewAt(e.union.Union.UnionType, ptr)
retVal.Elem().Set(val)
} else {
val := reflect.New(typ)
iter.ReadVal(val.Interface())
retVal := reflect.NewAt(e.union.Union.UnionType, ptr)
retVal.Elem().Set(val.Elem())
}
if iter.ReadObject() != "" {
iter.ReportError("decode UnionType", "there should be only one fields in the json object")
}
}
func makeDerefFullTypeName(typ reflect.Type) string {
realType := typ
for realType.Kind() == reflect.Pointer {
realType = realType.Elem()
}
return fmt.Sprintf("%s.%s", realType.PkgPath(), realType.Name())
}

View File

@ -0,0 +1,278 @@
package serder
import (
"bytes"
"encoding/json"
"fmt"
"io"
"reflect"
"strings"
jsoniter "github.com/json-iterator/go"
"github.com/mitchellh/mapstructure"
)
var unionHandler = UnionHandler{
internallyTagged: make(map[reflect.Type]*anyTypeUnionInternallyTagged),
externallyTagged: make(map[reflect.Type]*anyTypeUnionExternallyTagged),
}
var defaultAPI = func() jsoniter.API {
api := jsoniter.Config{
EscapeHTML: true,
}.Froze()
api.RegisterExtension(&unionHandler)
return api
}()
// 将对象转为JSON字符串。支持TypeUnion。
func ObjectToJSONEx[T any](obj T) ([]byte, error) {
buf := new(bytes.Buffer)
enc := defaultAPI.NewEncoder(buf)
// 这里使用&obj而直接不使用obj的原因是Encode的形参类型为any
// 如果T是一个interface类型将obj传递进去后内部拿到的类型将会是obj的实际类型
// 使用&obj那么内部拿到的将会是*T类型通过一层一层解引用查找Encoder时能找到T对应的TypeUnion
err := enc.Encode(&obj)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// 将JSON字符串转为对象。支持TypeUnion。
func JSONToObjectEx[T any](data []byte) (T, error) {
var ret T
dec := defaultAPI.NewDecoder(bytes.NewReader(data))
err := dec.Decode(&ret)
if err != nil {
return ret, err
}
return ret, nil
}
// 将JSON字符串转为对象。支持TypeUnion。
func JSONToObjectExRaw(data []byte, ret any) error {
dec := defaultAPI.NewDecoder(bytes.NewReader(data))
err := dec.Decode(&ret)
if err != nil {
return err
}
return nil
}
// 将JSON字符串转为对象。支持TypeUnion。
//
// 如果发现反序列化后的结果不对但没有返回错误可以考虑是JSON字符串有问题
// 尤其是在反序列化嵌套的TypeUnion时如果内部的TypeUnion反序列化失败错误是不会传递出来的库的缺陷
func JSONToObjectStreamEx[T any](stream io.Reader) (T, error) {
var ret T
dec := defaultAPI.NewDecoder(stream)
err := dec.Decode(&ret)
if err != nil {
return ret, err
}
return ret, nil
}
func JSONToObjectStreamExRaw(stream io.Reader, ret any) error {
dec := defaultAPI.NewDecoder(stream)
err := dec.Decode(ret)
if err != nil {
return err
}
return nil
}
// 将对象转为JSON字符串。如果需要支持解析TypeUnion类型则使用"Ex"结尾的同名函数。
//
// 注:[]byte会被base64编码如果要JSON内容要给外部解析那么应该避免使用[]byte。
func ObjectToJSON(obj any) ([]byte, error) {
return json.Marshal(obj)
}
// 将对象转为JSON字符串。如果需要支持解析TypeUnion类型则使用"Ex"结尾的同名函数。
func ObjectToJSONStream(obj any) io.ReadCloser {
pr, pw := io.Pipe()
enc := json.NewEncoder(pw)
go func() {
err := enc.Encode(obj)
if err != nil && err != io.EOF {
pw.CloseWithError(err)
} else {
pw.Close()
}
}()
return pr
}
// 将JSON字符串转为对象。如果需要支持解析TypeUnion类型则使用"Ex"结尾的同名函数。
func JSONToObject(data []byte, obj any) error {
return json.Unmarshal(data, obj)
}
// 将JSON字符串转为对象。如果需要支持解析TypeUnion类型则使用"Ex"结尾的同名函数。
func JSONToObjectStream(str io.Reader, obj any) error {
dec := json.NewDecoder(str)
err := dec.Decode(obj)
if err != io.EOF {
return err
}
return nil
}
type TypeResolver interface {
TypeToString(typ reflect.Type) (string, error)
StringToType(typeStr string) (reflect.Type, error)
}
type MapToObjectOption struct {
NoRegisteredUnionTypes bool // 是否不使用全局注册的UnionType
}
// TODO 使用这个函数来处理TypeUnion的地方都可以直接使用Ex系列的函数
func MapToObject(m map[string]any, obj any, opt ...MapToObjectOption) error {
var op MapToObjectOption
if len(opt) > 0 {
op = opt[0]
}
unionTypeMapping := make(map[reflect.Type]*anyTypeUnionInternallyTagged)
if !op.NoRegisteredUnionTypes {
for _, u := range unionHandler.internallyTagged {
unionTypeMapping[u.Union.UnionType] = u
}
}
convs := []Converter{
func(from reflect.Value, to reflect.Value) (interface{}, error) {
toType := to.Type()
info, ok := unionTypeMapping[toType]
if !ok {
return from.Interface(), nil
}
mp := from.Interface().(map[string]any)
tag, ok := mp[info.TagField]
if !ok {
return nil, fmt.Errorf("converting to %v: no tag field %s in map", toType, info.TagField)
}
tagStr, ok := tag.(string)
if !ok {
return nil, fmt.Errorf("converting to %v: tag field %s value is %v, which is not a string", toType, info.TagField, tag)
}
eleType, ok := info.TagToType[tagStr]
if !ok {
return nil, fmt.Errorf("converting to %v: unknow type tag %s", toType, tagStr)
}
to.Set(reflect.New(eleType).Elem())
return from.Interface(), nil
},
}
return AnyToAny(m, obj, AnyToAnyOption{
Converters: convs,
})
}
func ObjectToMap(obj any) (map[string]any, error) {
mp := make(map[string]any)
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
TagName: "json",
Result: &mp,
})
if err != nil {
return nil, err
}
return mp, dec.Decode(obj)
}
// 1. 尝试解开所有引用
//
// 2. nil值将会是空字符串
func ObjectToMapString(obj any) (map[string]string, error) {
if obj == nil {
return make(map[string]string), nil
}
v := reflect.ValueOf(obj)
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
if !v.IsValid() {
return make(map[string]string), nil
}
if v.Kind() != reflect.Struct {
return nil, fmt.Errorf("type %v is not a struct", v.Type())
}
mp := make(map[string]string)
objectToMapString(v, mp)
return mp, nil
}
func objectToMapString(val reflect.Value, mp map[string]string) {
typ := val.Type()
for i := 0; i < val.NumField(); i++ {
vf := val.Field(i)
tf := typ.Field(i)
if tf.Anonymous {
objectToMapString(vf, mp)
continue
}
fieldName := tf.Name
omitEmpty := false
jsonTag := tf.Tag.Get("json")
if jsonTag != "" {
tagParts := strings.Split(jsonTag, ",")
fieldName = strings.TrimSpace(tagParts[0])
if len(tagParts) > 1 {
for _, tagPart := range tagParts[1:] {
tagPart = strings.TrimSpace(tagPart)
if tagPart == "omitempty" {
omitEmpty = true
}
}
}
}
for vf.Kind() == reflect.Ptr {
vf = vf.Elem()
}
if !vf.IsValid() {
if omitEmpty {
continue
}
mp[fieldName] = ""
continue
}
if vf.IsZero() && omitEmpty {
continue
}
if vf.Kind() == reflect.Array {
}
mp[fieldName] = fmt.Sprintf("%v", vf)
}
}

View File

@ -0,0 +1,801 @@
package serder
import (
"fmt"
"reflect"
"testing"
. "github.com/smartystreets/goconvey/convey"
"gitlink.org.cn/JointCloud/pcm-participant-common/pkgs/types"
"gitlink.org.cn/JointCloud/pcm-participant-common/utils/reflect2"
)
type FromAnyString struct {
Str string
}
func (a *FromAnyString) FromAny(val any) (bool, error) {
if str, ok := val.(string); ok {
a.Str = "@" + str
return true, nil
}
return false, nil
}
type ToAnyString struct {
Str string
}
func (a *ToAnyString) ToAny(typ reflect.Type) (val any, ok bool, err error) {
if typ == reflect2.TypeOf[map[string]any]() {
return map[string]any{
"str": "@" + a.Str,
}, true, nil
}
return nil, false, nil
}
type FromAnySt struct {
Value string
}
func (a *FromAnySt) FromAny(val any) (bool, error) {
if st, ok := val.(ToAnySt); ok {
a.Value = "From:" + st.Value
return true, nil
}
return false, nil
}
type ToAnySt struct {
Value string
}
func (a *ToAnySt) ToAny(typ reflect.Type) (val any, ok bool, err error) {
if typ == reflect2.TypeOf[FromAnySt]() {
return FromAnySt{
Value: "To:" + a.Value,
}, true, nil
}
return nil, false, nil
}
type DirToAnySt struct {
Value string
}
func (a DirToAnySt) ToAny(typ reflect.Type) (val any, ok bool, err error) {
if typ == reflect2.TypeOf[FromAnySt]() {
return FromAnySt{
Value: "DirTo:" + a.Value,
}, true, nil
}
return nil, false, nil
}
func Test_AnyToAny(t *testing.T) {
Convey("包含用字符串保存的int数据", t, func() {
type Struct struct {
A string `json:"a"`
B int `json:"b"`
C int64 `json:"c,string"`
}
mp := map[string]any{
"a": "a",
"b": 1,
"c": "1234",
}
var st Struct
err := AnyToAny(mp, &st)
So(err, ShouldBeNil)
So(st.A, ShouldEqual, "a")
So(st.B, ShouldEqual, 1)
So(st.C, ShouldEqual, 1234)
})
Convey("只有FromAny", t, func() {
type Struct struct {
Special FromAnyString `json:"str"`
}
mp := map[string]any{
"str": "test",
}
var ret Struct
err := AnyToAny(mp, &ret)
So(err, ShouldBeNil)
So(ret.Special.Str, ShouldEqual, "@test")
})
Convey("字段类型直接实现了FromAny", t, func() {
type Struct struct {
Special *FromAnyString `json:"str"`
}
mp := map[string]any{
"str": "test",
}
var ret Struct
err := AnyToAny(mp, &ret)
So(err, ShouldBeNil)
So(ret.Special.Str, ShouldEqual, "@test")
})
Convey("只有ToAny", t, func() {
st := struct {
Special ToAnyString `json:"str"`
}{
Special: ToAnyString{
Str: "test",
},
}
ret := map[string]any{}
err := AnyToAny(st, &ret)
So(err, ShouldBeNil)
So(ret["str"].(map[string]any)["str"], ShouldEqual, "@test")
})
Convey("优先使用ToAny", t, func() {
st1 := ToAnySt{
Value: "test",
}
st2 := FromAnySt{}
err := AnyToAny(st1, &st2)
So(err, ShouldBeNil)
So(st2.Value, ShouldEqual, "To:test")
})
Convey("使用Convertor", t, func() {
type Struct1 struct {
Value string
}
type Struct2 struct {
Value string
}
st1 := Struct1{
Value: "test",
}
st2 := Struct2{}
err := AnyToAny(st1, &st2, AnyToAnyOption{
Converters: []Converter{func(from reflect.Value, to reflect.Value) (interface{}, error) {
if from.Type() == reflect2.TypeOf[Struct1]() && to.Type() == reflect2.TypeOf[Struct2]() {
s1 := from.Interface().(Struct1)
return Struct2{
Value: "@" + s1.Value,
}, nil
}
return nil, fmt.Errorf("should not arrive here!")
}},
})
So(err, ShouldBeNil)
So(st2.Value, ShouldEqual, "@test")
})
}
func Test_MapToObject(t *testing.T) {
type Base struct {
Int int
Bool bool
String string
Float float32
}
type ArraryStruct struct {
IntArr []int
StArr []Base
ArrArr [][]int
Nil []Base
}
type MapStruct struct {
StrMap map[string]string
StMap map[string]Base
MapMap map[string]map[string]string
Nil map[string]Base
}
type Top struct {
ArrSt ArraryStruct
MapSt *MapStruct
BaseIf any
NilPtr *Base
}
Convey("结构体递归转换成map[string]any", t, func() {
val := Top{
ArrSt: ArraryStruct{
IntArr: []int{1, 2, 3},
StArr: []Base{
{
Int: 1,
Bool: true,
String: "test",
Float: 1,
},
{
Int: 2,
Bool: false,
String: "test2",
Float: 2,
},
},
ArrArr: [][]int{
{1, 2, 3},
{},
nil,
},
Nil: nil,
},
MapSt: &MapStruct{
StrMap: map[string]string{
"a": "1",
"b": "2",
},
StMap: map[string]Base{
"a": {
Int: 1,
Bool: true,
String: "test",
Float: 1,
},
"b": {
Int: 2,
Bool: false,
String: "test2",
Float: 2,
},
},
MapMap: map[string]map[string]string{
"a": {
"a": "1",
"b": "2",
},
"b": nil,
},
Nil: nil,
},
BaseIf: Base{
Int: 1,
Bool: true,
String: "test",
Float: 1,
},
NilPtr: nil,
}
retMp, err := ObjectToMap(val)
So(err, ShouldBeNil)
exceptMap := map[string]any{
"ArrSt": map[string]any{
"IntArr": []any{1, 2, 3},
"StArr": []any{
map[string]any{
"Int": 1,
"Bool": true,
"String": "test",
"Float": 1,
},
map[string]any{
"Int": 2,
"Bool": false,
"String": "test2",
"Float": 2,
},
},
"ArrArr": []any{
[]any{1, 2, 3},
[]any{},
[]int(nil),
},
"Nil": []Base(nil),
},
"MapSt": map[string]any{
"StrMap": map[string]any{
"a": "1",
"b": "2",
},
"StMap": map[string]any{
"a": map[string]any{
"Int": 1,
"Bool": true,
"String": "test",
"Float": 1,
},
"b": map[string]any{
"Int": 2,
"Bool": false,
"String": "test2",
"Float": 2,
},
},
"MapMap": map[string]any{
"a": map[string]any{
"a": "1",
"b": "2",
},
"b": map[string]string(nil),
},
"Nil": map[string]Base(nil),
},
"BaseIf": map[string]any{
"Int": 1,
"Bool": true,
"String": "test",
"Float": 1,
},
"NilPtr": (*Base)(nil),
}
mpRetJson, err := ObjectToJSON(retMp)
So(err, ShouldBeNil)
exceptMapJson, err := ObjectToJSON(exceptMap)
So(err, ShouldBeNil)
So(string(mpRetJson), ShouldEqualJSON, string(exceptMapJson))
})
Convey("包含UnionType", t, func() {
type EleType string
type UnionType interface{}
type EleType1 struct {
Metadata `union:"1"`
Type EleType `json:"type"`
Value1 string `json:"value1"`
}
type EleType2 struct {
Metadata `union:"2"`
Type EleType `json:"type"`
Value2 int `json:"value2"`
}
type St struct {
Us []UnionType `json:"us"`
}
mp := map[string]any{
"us": []map[string]any{
{
"type": "1",
"value1": "1",
},
{
"type": "2",
"value2": 2,
},
},
}
var ret St
union := types.NewTypeUnion[UnionType](
(*EleType1)(nil),
(*EleType2)(nil),
)
UseTypeUnionInternallyTagged(&union, "type")
err := MapToObject(mp, &ret)
So(err, ShouldBeNil)
So(ret.Us, ShouldResemble, []UnionType{
&EleType1{Type: "1", Value1: "1"},
&EleType2{Type: "2", Value2: 2},
})
})
Convey("要转换到的结构体就是一个UnionType", t, func() {
type UnionType interface{}
type EleType1 struct {
Metadata `union:"1"`
Type string `json:"type"`
Value1 string `json:"value1"`
}
type EleType2 struct {
Metadata `union:"2"`
Type string `json:"type"`
Value2 int `json:"value2"`
}
mp := map[string]any{
"type": "1",
"value1": "1",
}
var ret UnionType
union := types.NewTypeUnion[UnionType](
(*EleType1)(nil),
(*EleType2)(nil),
)
UseTypeUnionInternallyTagged(&union, "type")
err := MapToObject(mp, &ret)
So(err, ShouldBeNil)
So(ret, ShouldResemble, &EleType1{Type: "1", Value1: "1"})
})
Convey("NewType", t, func() {
type Str string
type St struct {
Str Str
}
mp := map[string]any{
"Str": "1",
}
var ret St
err := MapToObject(mp, &ret)
So(err, ShouldBeNil)
So(string(ret.Str), ShouldEqual, "1")
})
}
type Base interface {
Noop()
}
type St1 struct {
Metadata `union:"St1"`
Type string
Val string
}
func (*St1) Noop() {}
type St2 struct {
Metadata `union:"St2"`
Type string
Val int
}
func (St2) Noop() {}
func Test_ObjectToJSON2(t *testing.T) {
Convey("NewType", t, func() {
type Str string
type St struct {
Str Str `json:"str"`
}
st := St{
Str: Str("1"),
}
data, err := ObjectToJSON(st)
So(err, ShouldBeNil)
var ret St
err = JSONToObject(data, &ret)
So(err, ShouldBeNil)
So(string(ret.Str), ShouldEqual, "1")
})
Convey("UnionType ExternallyTagged", t, func() {
type Base interface{}
type St1 struct {
Val string
}
type St2 struct {
Val int64
}
type Outter struct {
B []Base
}
union := types.NewTypeUnion[Base](St1{}, &St2{})
UseTypeUnionExternallyTagged(&union)
val := Outter{B: []Base{St1{Val: "asd"}, &St2{Val: 123}}}
data, err := ObjectToJSONEx(val)
So(err, ShouldBeNil)
ret, err := JSONToObjectEx[Outter](data)
So(err, ShouldBeNil)
So(ret, ShouldResemble, val)
})
Convey("UnionType InternallyTagged", t, func() {
type Base interface{}
type St1 struct {
Metadata `union:"St1"`
Type string
Val string
}
type St2 struct {
Metadata `union:"St2"`
Type string
Val int64
}
type Outter struct {
B []Base
}
union := types.NewTypeUnion[Base](St1{}, &St2{})
UseTypeUnionInternallyTagged(&union, "Type")
val := Outter{B: []Base{St1{Val: "asd", Type: "St1"}, &St2{Val: 123, Type: "St2"}}}
data, err := ObjectToJSONEx(val)
So(err, ShouldBeNil)
ret, err := JSONToObjectEx[Outter](data)
So(err, ShouldBeNil)
So(ret, ShouldResemble, val)
})
Convey("实参类型和目标类型本身就是UnionType ExternallyTagged", t, func() {
type Base interface{}
type St1 struct {
Val string
}
union := types.NewTypeUnion[Base](St1{})
UseTypeUnionExternallyTagged(&union)
var val Base = St1{Val: "asd"}
data, err := ObjectToJSONEx(val)
So(err, ShouldBeNil)
ret, err := JSONToObjectEx[Base](data)
So(err, ShouldBeNil)
So(ret, ShouldResemble, val)
})
Convey("实参类型和目标类型本身就是UnionType InternallyTagged", t, func() {
type Base interface{}
type St1 struct {
Metadata `union:"St1"`
Type string
Val string
}
union := types.NewTypeUnion[Base](St1{})
UseTypeUnionInternallyTagged(&union, "Type")
var val Base = St1{Val: "asd", Type: "St1"}
data, err := ObjectToJSONEx(val)
So(err, ShouldBeNil)
ret, err := JSONToObjectEx[Base](data)
So(err, ShouldBeNil)
So(ret, ShouldResemble, val)
})
Convey("UnionType带有函数 ExternallyTagged", t, func() {
union := types.NewTypeUnion[Base](&St1{}, St2{})
UseTypeUnionExternallyTagged(&union)
var val = []Base{
&St1{Val: "asd", Type: "St1"},
St2{Val: 123, Type: "St2"},
}
data, err := ObjectToJSONEx(val)
So(err, ShouldBeNil)
ret, err := JSONToObjectEx[[]Base](data)
So(err, ShouldBeNil)
So(ret, ShouldResemble, val)
})
Convey("UnionType带有函数 InternallyTagged", t, func() {
union := types.NewTypeUnion[Base](&St1{}, St2{})
UseTypeUnionInternallyTagged(&union, "Type")
var val = []Base{
&St1{Val: "asd", Type: "St1"},
St2{Val: 123, Type: "St2"},
}
data, err := ObjectToJSONEx(val)
So(err, ShouldBeNil)
ret, err := JSONToObjectEx[[]Base](data)
So(err, ShouldBeNil)
So(ret, ShouldResemble, val)
})
Convey("UnionType但实际值为nil ExternallyTagged", t, func() {
union := types.NewTypeUnion[Base](&St1{}, St2{})
UseTypeUnionExternallyTagged(&union)
var val = []Base{
nil,
}
data, err := ObjectToJSONEx(val)
So(err, ShouldBeNil)
ret, err := JSONToObjectEx[[]Base](data)
So(err, ShouldBeNil)
So(ret, ShouldResemble, val)
})
Convey("UnionType但实际值为nil InternallyTagged", t, func() {
union := types.NewTypeUnion[Base](&St1{}, St2{})
UseTypeUnionInternallyTagged(&union, "Type")
var val = []Base{
nil,
}
data, err := ObjectToJSONEx(val)
So(err, ShouldBeNil)
ret, err := JSONToObjectEx[[]Base](data)
So(err, ShouldBeNil)
So(ret, ShouldResemble, val)
})
}
func Test_ObjectToJSON3(t *testing.T) {
Convey("反序列化TypeUnion时JSON中对应字段类型不对", t, func() {
type Base interface{}
union := types.NewTypeUnion[Base](&St1{}, &St2{})
UseTypeUnionInternallyTagged(&union, "Type")
v, err := JSONToObjectEx[[]Base]([]byte("[{\"Type\":\"St2\", \"Val\":[]}]"))
t.Logf("err: %v", err)
t.Logf("v: %+v", v[0])
So(err, ShouldNotBeNil)
// So(ret, ShouldResemble, val)
})
}
type BaseCallback interface{}
type StCallback struct {
Metadata `union:"StCallback"`
Type string
Value string
}
func (st *StCallback) OnUnionSerializing() {
st.Value = "called"
st.Type = "StCallback"
}
func Test_ObjectToJSONEx4(t *testing.T) {
Convey("序列化Callback", t, func() {
union := types.NewTypeUnion[BaseCallback](&StCallback{})
UseTypeUnionInternallyTagged(&union, "Type")
val := []BaseCallback{&StCallback{}}
data, err := ObjectToJSONEx(val)
So(err, ShouldBeNil)
ret, err := JSONToObjectEx[[]BaseCallback](data)
So(err, ShouldBeNil)
So(len(ret), ShouldEqual, 1)
So(ret[0].(*StCallback).Value, ShouldEqual, "called")
})
}
type StStringer struct {
}
func (s StStringer) String() string {
return "StStringer"
}
func Test_ObjectToMapString(t *testing.T) {
Convey("结构体", t, func() {
type StEmb struct {
IntRef *int `json:"intRef,omitempty"`
BoolRef **bool `json:"boolRef"`
StrRef *string `json:"strRef"`
}
type St struct {
StEmb
Int int
Bool bool
Str string
StStringer *StStringer
}
st := St{
StEmb: StEmb{
IntRef: types.Ref(123),
BoolRef: types.Ref(types.Ref(true)),
},
Int: 456,
Bool: false,
Str: "test",
StStringer: &StStringer{},
}
mp, err := ObjectToMapString(st)
So(err, ShouldBeNil)
So(mp["intRef"], ShouldEqual, "123")
So(mp["boolRef"], ShouldEqual, "true")
So(mp["strRef"], ShouldEqual, "")
So(mp["Int"], ShouldEqual, "456")
So(mp["Bool"], ShouldEqual, "false")
So(mp["Str"], ShouldEqual, "test")
So(mp["StStringer"], ShouldEqual, "StStringer")
})
Convey("结构体引用", t, func() {
type StEmb struct {
IntRef *int `json:"intRef,omitempty"`
BoolRef **bool `json:"boolRef"`
StrRef *string `json:"strRef"`
}
type St struct {
StEmb
Int int
Bool bool
Str string
StStringer *StStringer
}
st := St{
StEmb: StEmb{
IntRef: types.Ref(123),
BoolRef: types.Ref(types.Ref(true)),
},
Int: 456,
Bool: false,
Str: "test",
StStringer: &StStringer{},
}
mp, err := ObjectToMapString(&st)
So(err, ShouldBeNil)
So(mp["intRef"], ShouldEqual, "123")
So(mp["boolRef"], ShouldEqual, "true")
So(mp["strRef"], ShouldEqual, "")
So(mp["Int"], ShouldEqual, "456")
So(mp["Bool"], ShouldEqual, "false")
So(mp["Str"], ShouldEqual, "test")
So(mp["StStringer"], ShouldEqual, "StStringer")
})
Convey("nil", t, func() {
mp, err := ObjectToMapString(nil)
So(err, ShouldBeNil)
So(mp, ShouldResemble, map[string]string{})
})
Convey("nil指针", t, func() {
type St struct{}
var st *St
mp, err := ObjectToMapString(st)
So(err, ShouldBeNil)
So(mp, ShouldResemble, map[string]string{})
})
Convey("非结构体", t, func() {
mp, err := ObjectToMapString(123)
So(err, ShouldNotBeNil)
So(mp, ShouldBeNil)
})
}

View File

@ -0,0 +1,43 @@
package serder
import (
"fmt"
"reflect"
)
type StringTypeResolver struct {
strToType map[string]reflect.Type
typeToStr map[reflect.Type]string
}
func NewStringTypeResolver() *StringTypeResolver {
return &StringTypeResolver{
strToType: make(map[string]reflect.Type),
typeToStr: make(map[reflect.Type]string),
}
}
func (r *StringTypeResolver) Add(str string, typ reflect.Type) *StringTypeResolver {
r.strToType[str] = typ
r.typeToStr[typ] = str
return r
}
func (r *StringTypeResolver) TypeToString(typ reflect.Type) (string, error) {
var typeStr string
var ok bool
if typeStr, ok = r.typeToStr[typ]; !ok {
return "", fmt.Errorf("type %s is not registered before", typ)
}
return typeStr, nil
}
func (r *StringTypeResolver) StringToType(typeStr string) (reflect.Type, error) {
typ, ok := r.strToType[typeStr]
if !ok {
return nil, fmt.Errorf("unknow type string %s", typeStr)
}
return typ, nil
}

View File

@ -0,0 +1,48 @@
package serder
import (
"fmt"
"reflect"
)
type TypeNameResolver struct {
includePackagePath bool
types map[string]reflect.Type
}
func NewTypeNameResolver(includePackagePath bool) *TypeNameResolver {
return &TypeNameResolver{
includePackagePath: includePackagePath,
types: make(map[string]reflect.Type),
}
}
func (r *TypeNameResolver) Register(typ reflect.Type) {
r.types[makeTypeString(typ, r.includePackagePath)] = typ
}
func (r *TypeNameResolver) TypeToString(typ reflect.Type) (string, error) {
typeStr := makeTypeString(typ, r.includePackagePath)
if _, ok := r.types[typeStr]; !ok {
return "", fmt.Errorf("type %s is not registered before", typeStr)
}
return typeStr, nil
}
func (r *TypeNameResolver) StringToType(typeStr string) (reflect.Type, error) {
typ, ok := r.types[typeStr]
if !ok {
return nil, fmt.Errorf("unknow type name %s", typeStr)
}
return typ, nil
}
func makeTypeString(typ reflect.Type, includePkgPath bool) string {
if includePkgPath {
return fmt.Sprintf("%s.%s", typ.PkgPath(), typ.Name())
}
return typ.Name()
}

View File

@ -0,0 +1,47 @@
package serder
import (
"fmt"
"strconv"
"time"
"gitlink.org.cn/JointCloud/pcm-participant-common/utils/serder/types"
)
type Metadata = types.Metadata
type TimestampSecond time.Time
func (t *TimestampSecond) MarshalJSON() ([]byte, error) {
raw := time.Time(*t)
return []byte(fmt.Sprintf("%d", raw.Unix())), nil
}
func (t *TimestampSecond) UnmarshalJSON(data []byte) error {
var timestamp int64
var err error
if timestamp, err = strconv.ParseInt(string(data), 10, 64); err != nil {
return err
}
*t = TimestampSecond(time.Unix(timestamp, 0))
return nil
}
type TimestampMilliSecond time.Time
func (t *TimestampMilliSecond) MarshalJSON() ([]byte, error) {
raw := time.Time(*t)
return []byte(fmt.Sprintf("%d", raw.UnixMilli())), nil
}
func (t *TimestampMilliSecond) UnmarshalJSON(data []byte) error {
var timestamp int64
var err error
if timestamp, err = strconv.ParseInt(string(data), 10, 64); err != nil {
return err
}
*t = TimestampMilliSecond(time.UnixMilli(timestamp))
return nil
}

View File

@ -0,0 +1,7 @@
package types
type Metadata struct{}
type OnUnionSerializing interface {
OnUnionSerializing()
}

View File

@ -0,0 +1,35 @@
package serder
import (
"encoding/json"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Timestamp(t *testing.T) {
Convey("秒级时间戳", t, func() {
str := "1698894747"
var ts TimestampSecond
err := json.Unmarshal([]byte(str), &ts)
So(err, ShouldBeNil)
t := time.Time(ts)
So(t.Unix(), ShouldEqual, 1698894747)
})
Convey("毫秒级时间戳", t, func() {
str := "1698895130651"
var ts TimestampMilliSecond
err := json.Unmarshal([]byte(str), &ts)
So(err, ShouldBeNil)
t := time.Time(ts)
So(t.UnixMilli(), ShouldEqual, 1698895130651)
})
}

View File

@ -0,0 +1,373 @@
package serder
import (
"fmt"
"reflect"
"unsafe"
jsoniter "github.com/json-iterator/go"
"github.com/modern-go/reflect2"
"gitlink.org.cn/JointCloud/pcm-participant-common/pkgs/types"
sertypes "gitlink.org.cn/JointCloud/pcm-participant-common/utils/serder/types"
ref2 "gitlink.org.cn/JointCloud/pcm-participant-common/utils/reflect2"
)
type anyTypeUnionExternallyTagged struct {
Union *types.AnyTypeUnion
TypeNameToType map[string]reflect.Type
}
type TypeUnionExternallyTagged[T any] struct {
anyTypeUnionExternallyTagged
TUnion *types.TypeUnion[T]
}
// 遇到TypeUnion的基类UnionType的字段时将其实际值的类型信息也编码到JSON中反序列化时也会根据解析出类型信息还原出真实的类型。
// Externally Tagged的格式是{ "类型名": {...对象内容...} }
//
// 可以通过内嵌Metadata结构体并在它身上增加"union"Tag来指定类型名称如果没有指定则默认使用系统类型名包括包路径
func UseTypeUnionExternallyTagged[T any](union *types.TypeUnion[T]) *TypeUnionExternallyTagged[T] {
eu := &TypeUnionExternallyTagged[T]{
anyTypeUnionExternallyTagged: anyTypeUnionExternallyTagged{
Union: union.ToAny(),
TypeNameToType: make(map[string]reflect.Type),
},
TUnion: union,
}
for _, eleType := range union.ElementTypes {
eu.Add(eleType)
}
unionHandler.externallyTagged[union.UnionType] = &eu.anyTypeUnionExternallyTagged
return eu
}
func (u *TypeUnionExternallyTagged[T]) Add(typ reflect.Type) error {
err := u.TUnion.Add(typ)
if err != nil {
return nil
}
u.TypeNameToType[makeDerefFullTypeName(typ)] = typ
return nil
}
func (u *TypeUnionExternallyTagged[T]) AddT(nilValue T) error {
u.Add(reflect.TypeOf(nilValue))
return nil
}
type anyTypeUnionInternallyTagged struct {
Union *types.AnyTypeUnion
TagField string
TagToType map[string]reflect.Type
}
type TypeUnionInternallyTagged[T any] struct {
anyTypeUnionInternallyTagged
TUnion *types.TypeUnion[T]
}
// 遇到TypeUnion的基类UnionType的字段时将其实际值的类型信息也编码到JSON中反序列化时也会解析出类型信息还原出真实的类型。
// Internally Tagged的格式是{ "类型字段": "类型名", ...对象内容...}JSON中的类型字段名需要指定。
// 注:对象定义需要包含类型字段,而且在序列化之前需要手动赋值,目前不支持自动设置。
//
// 可以通过内嵌Metadata结构体并在它身上增加"union"Tag来指定类型名称如果没有指定则默认使用系统类型名包括包路径
func UseTypeUnionInternallyTagged[T any](union *types.TypeUnion[T], tagField string) *TypeUnionInternallyTagged[T] {
iu := &TypeUnionInternallyTagged[T]{
anyTypeUnionInternallyTagged: anyTypeUnionInternallyTagged{
Union: union.ToAny(),
TagField: tagField,
TagToType: make(map[string]reflect.Type),
},
TUnion: union,
}
for _, eleType := range union.ElementTypes {
iu.Add(eleType)
}
unionHandler.internallyTagged[union.UnionType] = &iu.anyTypeUnionInternallyTagged
return iu
}
func (u *TypeUnionInternallyTagged[T]) Add(typ reflect.Type) error {
err := u.Union.Add(typ)
if err != nil {
return nil
}
// 解引用直到得到结构体类型
structType := typ
for structType.Kind() == reflect.Pointer {
structType = structType.Elem()
}
// 要求内嵌Metadata结构体那么结构体中的字段名就会是Metadata
field, ok := structType.FieldByName(ref2.TypeNameOf[Metadata]())
if !ok {
u.TagToType[makeDerefFullTypeName(structType)] = typ
return nil
}
// 为防同名检查类型是不是也是Metadata
if field.Type != ref2.TypeOf[Metadata]() {
u.TagToType[makeDerefFullTypeName(structType)] = typ
return nil
}
tag := field.Tag.Get("union")
if tag == "" {
u.TagToType[makeDerefFullTypeName(structType)] = typ
return nil
}
u.TagToType[tag] = typ
return nil
}
func (u *TypeUnionInternallyTagged[T]) AddT(nilValue T) error {
u.Add(reflect.TypeOf(nilValue))
return nil
}
type UnionHandler struct {
internallyTagged map[reflect.Type]*anyTypeUnionInternallyTagged
externallyTagged map[reflect.Type]*anyTypeUnionExternallyTagged
}
func (h *UnionHandler) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
}
func (h *UnionHandler) CreateMapKeyDecoder(typ reflect2.Type) jsoniter.ValDecoder {
return nil
}
func (h *UnionHandler) CreateMapKeyEncoder(typ reflect2.Type) jsoniter.ValEncoder {
return nil
}
func (h *UnionHandler) CreateDecoder(typ reflect2.Type) jsoniter.ValDecoder {
typ1 := typ.Type1()
if it, ok := h.internallyTagged[typ1]; ok {
return &InternallyTaggedDecoder{
union: it,
}
}
if et, ok := h.externallyTagged[typ1]; ok {
return &ExternallyTaggedDecoder{
union: et,
}
}
return nil
}
func (h *UnionHandler) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder {
typ1 := typ.Type1()
if it, ok := h.internallyTagged[typ1]; ok {
return &InternallyTaggedEncoder{
union: it,
}
}
if et, ok := h.externallyTagged[typ1]; ok {
return &ExternallyTaggedEncoder{
union: et,
}
}
return nil
}
func (h *UnionHandler) DecorateDecoder(typ reflect2.Type, decoder jsoniter.ValDecoder) jsoniter.ValDecoder {
return decoder
}
func (h *UnionHandler) DecorateEncoder(typ reflect2.Type, encoder jsoniter.ValEncoder) jsoniter.ValEncoder {
return encoder
}
// 以下Encoder/Decoder都是在传入类型/目标类型是TypeUnion的基类UnionType时使用
type InternallyTaggedEncoder struct {
union *anyTypeUnionInternallyTagged
}
func (e *InternallyTaggedEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return false
}
func (e *InternallyTaggedEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
var val any
if e.union.Union.UnionType.NumMethod() == 0 {
// 无方法的interface底层都是eface结构体所以可以直接转*any
val = *(*any)(ptr)
} else {
// 有方法的interface底层都是iface结构体可以将其转成eface转换后不损失类型信息
val = reflect2.IFaceToEFace(ptr)
}
if val != nil {
if on, ok := val.(sertypes.OnUnionSerializing); ok {
on.OnUnionSerializing()
}
}
// 可以考虑检查一下Type字段有没有赋值没有赋值则将其赋值为union Tag指定的值
stream.WriteVal(val)
}
type InternallyTaggedDecoder struct {
union *anyTypeUnionInternallyTagged
}
func (e *InternallyTaggedDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
nextTokenKind := iter.WhatIsNext()
if nextTokenKind == jsoniter.NilValue {
iter.Skip()
return
}
raw := iter.ReadAny()
if raw.LastError() != nil {
iter.ReportError("decode TaggedUnionType", "getting object raw:"+raw.LastError().Error())
return
}
tagField := raw.Get(e.union.TagField)
if tagField.LastError() != nil {
iter.ReportError("decode TaggedUnionType", "getting type tag field:"+tagField.LastError().Error())
return
}
typeTag := tagField.ToString()
if typeTag == "" {
iter.ReportError("decode TaggedUnionType", "type tag is empty")
return
}
typ, ok := e.union.TagToType[typeTag]
if !ok {
iter.ReportError("decode TaggedUnionType", fmt.Sprintf("unknow type tag %s in union %s", typeTag, e.union.Union.UnionType.Name()))
return
}
// 如果目标类型已经是个指针类型*T那么在New的时候就需要使用T
// 否则New出来的是会是**T这将导致后续的反序列化出问题
if typ.Kind() == reflect.Pointer {
val := reflect.New(typ.Elem())
raw.ToVal(val.Interface()) // TODO 使用的库丢失了ToVal期间的错误信息考虑换个库
retVal := reflect.NewAt(e.union.Union.UnionType, ptr)
retVal.Elem().Set(val)
} else {
val := reflect.New(typ)
raw.ToVal(val.Interface())
retVal := reflect.NewAt(e.union.Union.UnionType, ptr)
retVal.Elem().Set(val.Elem())
}
}
type ExternallyTaggedEncoder struct {
union *anyTypeUnionExternallyTagged
}
func (e *ExternallyTaggedEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return false
}
func (e *ExternallyTaggedEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
var val any
if e.union.Union.UnionType.NumMethod() == 0 {
// 无方法的interface底层都是eface结构体所以可以直接转*any
val = *(*any)(ptr)
} else {
// 有方法的interface底层都是iface结构体可以将其转成eface转换后不损失类型信息
val = reflect2.IFaceToEFace(ptr)
}
if val == nil {
stream.WriteNil()
return
}
if on, ok := val.(sertypes.OnUnionSerializing); ok {
on.OnUnionSerializing()
}
stream.WriteObjectStart()
valType := ref2.TypeOfValue(val)
if !e.union.Union.Include(valType) {
stream.Error = fmt.Errorf("type %v is not in union %v", valType, e.union.Union.UnionType)
return
}
stream.WriteObjectField(makeDerefFullTypeName(valType))
stream.WriteVal(val)
stream.WriteObjectEnd()
}
type ExternallyTaggedDecoder struct {
union *anyTypeUnionExternallyTagged
}
func (e *ExternallyTaggedDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
nextTkType := iter.WhatIsNext()
if nextTkType == jsoniter.NilValue {
iter.Skip()
return
}
if nextTkType != jsoniter.ObjectValue {
iter.ReportError("decode UnionType", fmt.Sprintf("unknow next token type %v", nextTkType))
return
}
typeStr := iter.ReadObject()
if typeStr == "" {
iter.ReportError("decode UnionType", "type string is empty")
}
typ, ok := e.union.TypeNameToType[typeStr]
if !ok {
iter.ReportError("decode UnionType", fmt.Sprintf("unknow type string %s in union %v", typeStr, e.union.Union.UnionType))
return
}
// 如果目标类型已经是个指针类型*T那么在New的时候就需要使用T
// 否则New出来的是会是**T这将导致后续的反序列化出问题
if typ.Kind() == reflect.Pointer {
val := reflect.New(typ.Elem())
iter.ReadVal(val.Interface())
retVal := reflect.NewAt(e.union.Union.UnionType, ptr)
retVal.Elem().Set(val)
} else {
val := reflect.New(typ)
iter.ReadVal(val.Interface())
retVal := reflect.NewAt(e.union.Union.UnionType, ptr)
retVal.Elem().Set(val.Elem())
}
if iter.ReadObject() != "" {
iter.ReportError("decode UnionType", "there should be only one fields in the json object")
}
}
func makeDerefFullTypeName(typ reflect.Type) string {
realType := typ
for realType.Kind() == reflect.Pointer {
realType = realType.Elem()
}
return fmt.Sprintf("%s.%s", realType.PkgPath(), realType.Name())
}

View File

@ -0,0 +1,150 @@
package serder
import (
"fmt"
"reflect"
"testing"
. "github.com/smartystreets/goconvey/convey"
"gitlink.org.cn/JointCloud/pcm-participant-common/utils/reflect2"
)
func Test_WalkValue(t *testing.T) {
type Base struct {
Int int
Bool bool
String string
Float float32
}
type ArraryStruct struct {
IntArr []int
StArr []Base
ArrArr [][]int
Nil []Base
}
type MapStruct struct {
StrMap map[string]string
StMap map[string]Base
MapMap map[string]map[string]string
Nil map[string]Base
}
type Top struct {
ArrSt ArraryStruct
MapSt *MapStruct
BaseIf any
NilPtr *Base
}
isBaseDataType := func(val reflect.Value) bool {
typ := val.Type()
return typ == reflect2.TypeOf[int]() || typ == reflect2.TypeOf[bool]() ||
typ == reflect2.TypeOf[string]() || typ == reflect2.TypeOf[float32]() || val.IsZero()
}
toString := func(val any) string {
return fmt.Sprintf("%v", val)
}
Convey("遍历", t, func() {
val := Top{
ArrSt: ArraryStruct{
IntArr: []int{1, 2, 3},
StArr: []Base{
{
Int: 1,
Bool: true,
String: "test",
Float: 1,
},
{
Int: 2,
Bool: false,
String: "test2",
Float: 2,
},
},
ArrArr: [][]int{
{1, 2, 3},
{},
nil,
},
Nil: nil,
},
MapSt: &MapStruct{
StrMap: map[string]string{
"a": "1",
"b": "2",
},
StMap: map[string]Base{
"a": {
Int: 1,
Bool: true,
String: "test",
Float: 1,
},
"b": {
Int: 2,
Bool: false,
String: "test2",
Float: 2,
},
},
MapMap: map[string]map[string]string{
"a": {
"a": "1",
"b": "2",
},
"b": nil,
},
Nil: nil,
},
BaseIf: Base{
Int: 1,
Bool: true,
String: "test",
Float: 1,
},
NilPtr: nil,
}
var trace []string
WalkValue(val, func(ctx *WalkContext, event WalkEvent) WalkingOp {
switch e := event.(type) {
case StructBeginEvent:
trace = append(trace, "StructBeginEvent")
case StructArriveFieldEvent:
trace = append(trace, "StructFieldEvent", e.Info.Name)
if isBaseDataType(e.Value) {
trace = append(trace, toString(e.Value.Interface()))
}
case StructEndEvent:
trace = append(trace, "StructEndEvent")
case MapBeginEvent:
trace = append(trace, "MapBeginEvent")
case MapArriveEntryEvent:
trace = append(trace, "MapEntryEvent", e.Key.String())
if isBaseDataType(e.Value) {
trace = append(trace, toString(e.Value.Interface()))
}
case MapEndEvent:
trace = append(trace, "MapEndEvent")
case ArrayBeginEvent:
trace = append(trace, "ArrayBeginEvent")
case ArrayArriveElementEvent:
trace = append(trace, "ArrayElementEvent", fmt.Sprintf("%d", e.Index))
if isBaseDataType(e.Value) {
trace = append(trace, toString(e.Value.Interface()))
}
case ArrayEndEvent:
trace = append(trace, "ArrayEndEvent")
}
return Next
})
So(trace, ShouldResemble, []string{})
})
}

View File

@ -0,0 +1,278 @@
package serder
import (
"reflect"
"github.com/zyedidia/generic/stack"
)
type WalkEvent interface{}
type StructBeginEvent struct {
Value reflect.Value
}
type StructArriveFieldEvent struct {
Info reflect.StructField
Value reflect.Value
}
type StructLeaveFieldEvent struct {
Info reflect.StructField
Value reflect.Value
}
type StructEndEvent struct {
Value reflect.Value
}
type ArrayBeginEvent struct {
Value reflect.Value
}
type ArrayArriveElementEvent struct {
Index int
Value reflect.Value
}
type ArrayLeaveElementEvent struct {
Index int
Value reflect.Value
}
type ArrayEndEvent struct {
Value reflect.Value
}
type MapBeginEvent struct {
Value reflect.Value
}
type MapArriveEntryEvent struct {
Key reflect.Value
Value reflect.Value
}
type MapLeaveEntryEvent struct {
Key reflect.Value
Value reflect.Value
}
type MapEndEvent struct {
Value reflect.Value
}
type WalkingOp int
const (
Next WalkingOp = iota
Skip
Stop
)
type Walker func(ctx *WalkContext, event WalkEvent) WalkingOp
type WalkContext struct {
stack *stack.Stack[any]
}
func (c *WalkContext) StackPush(val any) {
c.stack.Push(val)
}
func (c *WalkContext) StackPop() any {
return c.stack.Pop()
}
func (c *WalkContext) StackPeek() any {
return c.stack.Peek()
}
type WalkOption struct {
StackValues []any
}
func WalkValue(value any, walker Walker, opts ...WalkOption) *WalkContext {
var opt WalkOption
if len(opts) > 0 {
opt = opts[0]
}
ctx := &WalkContext{
stack: stack.New[any](),
}
for _, v := range opt.StackValues {
ctx.StackPush(v)
}
doWalking(ctx, reflect.ValueOf(value), walker)
return ctx
}
func doWalking(ctx *WalkContext, val reflect.Value, walker Walker) WalkingOp {
if !WillWalkInto(val) {
return Next
}
switch val.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if walker(ctx, ArrayBeginEvent{Value: val}) == Stop {
return Stop
}
for i := 0; i < val.Len(); i++ {
eleVal := val.Index(i)
op := walker(ctx, ArrayArriveElementEvent{
Index: i,
Value: eleVal,
})
if op == Skip {
if walker(ctx, ArrayLeaveElementEvent{
Index: i,
Value: eleVal,
}) == Stop {
return Stop
}
continue
}
if op == Stop {
return Stop
}
if doWalking(ctx, eleVal, walker) == Stop {
return Stop
}
if walker(ctx, ArrayLeaveElementEvent{
Index: i,
Value: eleVal,
}) == Stop {
return Stop
}
}
if walker(ctx, ArrayEndEvent{Value: val}) == Stop {
return Stop
}
case reflect.Map:
if walker(ctx, MapBeginEvent{Value: val}) == Stop {
return Stop
}
keys := val.MapKeys()
for _, key := range keys {
val := val.MapIndex(key)
op := walker(ctx, MapArriveEntryEvent{
Key: key,
Value: val,
})
if op == Skip {
if walker(ctx, MapLeaveEntryEvent{
Key: key,
Value: val,
}) == Stop {
return Stop
}
continue
}
if op == Stop {
return Stop
}
if doWalking(ctx, val, walker) == Stop {
return Stop
}
if walker(ctx, MapLeaveEntryEvent{
Key: key,
Value: val,
}) == Stop {
return Stop
}
}
if walker(ctx, MapEndEvent{Value: val}) == Stop {
return Stop
}
case reflect.Struct:
if walker(ctx, StructBeginEvent{Value: val}) == Stop {
return Stop
}
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
op := walker(ctx, StructArriveFieldEvent{
Info: val.Type().Field(i),
Value: field,
})
if op == Skip {
if walker(ctx, StructLeaveFieldEvent{
Info: val.Type().Field(i),
Value: field,
}) == Stop {
return Stop
}
continue
}
if op == Stop {
return Stop
}
if doWalking(ctx, field, walker) == Stop {
return Stop
}
if walker(ctx, StructLeaveFieldEvent{
Info: val.Type().Field(i),
Value: field,
}) == Stop {
return Stop
}
}
if walker(ctx, StructEndEvent{Value: val}) == Stop {
return Stop
}
case reflect.Interface:
fallthrough
case reflect.Pointer:
eleVal := val.Elem()
return doWalking(ctx, eleVal, walker)
}
return Next
}
const (
WillWalkIntoTypeKinds = (1 << reflect.Array) | (1 << reflect.Map) | (1 << reflect.Slice) | (1 << reflect.Struct)
)
func WillWalkInto(val reflect.Value) bool {
if val.IsZero() {
return false
}
typ := val.Type()
typeKind := typ.Kind()
if typeKind == reflect.Interface || typeKind == reflect.Pointer {
return WillWalkInto(val.Elem())
}
return ((1 << typeKind) & WillWalkIntoTypeKinds) != 0
}

3
go.mod
View File

@ -1,3 +0,0 @@
module gitlink.org.cn/JointCloud/pcm-participant
go 1.24.1

11
go.work Normal file
View File

@ -0,0 +1,11 @@
go 1.23.0
toolchain go1.24.0
use (
./common
./client
./platform
)
replace gitlink.org.cn/JointCloud/pcm-participant-common v0.0.0 => ./common

46
go.work.sum Normal file
View File

@ -0,0 +1,46 @@
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/knz/go-libedit v1.10.1 h1:0pHpWtx9vcvC0xGZqEQlQdfSQs7WRlAjuPvk3fOZDCo=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86 h1:D6paGObi5Wud7xg83MaEFyjxQB1W5bz5d0IFppr+ymk=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c h1:bY6ktFuJkt+ZXkX0RChQch2FtHpWQLVS8Qo1YasiIVk=
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636 h1:aSISeOcal5irEhJd1M+IrApc0PdcN7e7Aj4yuEnOrfQ=
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU=
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20220218215828-6cf2b201936e h1:iWVPgObh6F4UDtjBLK51zsy5UHTPLQwCmsNjCsbKhQ0=
golang.org/x/exp v0.0.0-20220218215828-6cf2b201936e/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
nullprogram.com/x/optparse v1.0.0 h1:xGFgVi5ZaWOnYdac2foDT3vg0ZZC9ErXFV57mr4OHrI=
rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=

60
hpc/go.sum Normal file
View File

@ -0,0 +1,60 @@
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

3
platform/go.mod Normal file
View File

@ -0,0 +1,3 @@
module gitlink.org.cn/JointCloud/pcm-participant-platform
go 1.23.0