From e8846f90db911895d5160da8029b380598f0cccd Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Sat, 28 Jun 2025 16:33:49 +0800 Subject: [PATCH 01/19] =?UTF-8?q?(kafka):=20=E5=8C=85=E8=A3=85?= =?UTF-8?q?=E4=BA=86sarama=E5=8C=85=E7=9A=84=E7=94=9F=E4=BA=A7=E6=B6=88?= =?UTF-8?q?=E8=B4=B9=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/kafka/main.go | 116 +++++++++++++++++++++++++++++++++++++ go.mod | 26 +++++++-- go.sum | 52 +++++++++++++++++ pkg/kafka/consumer.go | 97 +++++++++++++++++++++++++++++++ pkg/kafka/producer.go | 132 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 418 insertions(+), 5 deletions(-) create mode 100644 example/kafka/main.go create mode 100644 pkg/kafka/consumer.go create mode 100644 pkg/kafka/producer.go diff --git a/example/kafka/main.go b/example/kafka/main.go new file mode 100644 index 0000000..83eeb5e --- /dev/null +++ b/example/kafka/main.go @@ -0,0 +1,116 @@ +package main + +import ( + "context" + "log" + "time" + + "github.com/IBM/sarama" + "github.com/muxi-Infra/muxi-micro/pkg/kafka" +) + +// 同步生产者示例 +func SyncProducer() { + p := kafka.NewSyncConfig([]string{"localhost:9092"}) + //可自行改配置如:(可选) + //p.GetConfig().Producer.RequiredAcks = sarama.WaitForAll + + err := p.CreateProducer() + if err != nil { + log.Fatal(err) + } + + partition, offset, err := p.SendMessage("study2", "testkey8", "testvalue8") + if err != nil { + log.Fatal(err) + } + log.Printf("partition: %d, offset: %d\n", partition, offset) + + err = p.Close() + if err != nil { + log.Fatal(err) + } +} + +// 异步生产者示例 +func AsyncProducer() { + p := kafka.NewAsyncConfig([]string{"localhost:9092"}) + //可自行改配置如:(可选) + p.GetConfig().Producer.Return.Successes = true + + err := p.CreateProducer() + if err != nil { + log.Fatal(err) + } + + //异步获取成功消息 + ch := p.GetSuccess() + //或 ch:= p.GetError() + go func() { + for msg := range ch { + log.Printf("partition: %d, offset: %d, key: %s, value: %s\n", msg.Partition, msg.Offset, msg.Key, msg.Value) + } + }() + + p.SendMessage("study2", "testkey5", "testvalue5") + if err != nil { + log.Fatal(err) + } + + time.Sleep(time.Second * 5) + + err = p.Close() + if err != nil { + log.Fatal(err) + } + +} + +// 消费者示例 +func Consumer() { + // 先构造 handler 实现 ConsumerGroupHandler 接口 + // setup, cleanup, consumeclaim 都要用户自行实现 + fn := func(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error { + for msg := range claim.Messages() { + log.Println("partition: ", msg.Partition, "offset: ", msg.Offset, "key: ", string(msg.Key), "value: ", string(msg.Value)) + session.MarkMessage(msg, "") + } + return nil // 正常退出 + } + handler := kafka.NewHandler(nil, nil, fn) + + // 构造消费者组 + c := kafka.NewConsumerConfig([]string{"localhost:9092"}, "test-group", []string{"study2"}, handler) + //可自行改配置如:(可选) + //c.GetConfig().Consumer.Offsets.Initial = sarama.OffsetOldest + + err := c.CreateConsumerGroup() + if err != nil { + log.Fatal(err) + } + + // 消费消息 + ctx, cancel := context.WithCancel(context.Background()) + + // 取消消费 + go func() { + time.Sleep(time.Second * 10) + cancel() + }() + + err = c.Consume(ctx) + if err != nil { + log.Fatal(err) + } + + err = c.Close() + if err != nil { + log.Fatal(err) + } +} + +func main() { + SyncProducer() + //AsyncProducer() + Consumer() +} diff --git a/go.mod b/go.mod index d39a222..d9ce4ce 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( ) require ( + github.com/IBM/sarama v1.45.2 // indirect github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 // indirect github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect github.com/alibabacloud-go/darabonba-array v0.1.0 // indirect @@ -39,22 +40,37 @@ require ( github.com/clbanning/mxj/v2 v2.5.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set v1.7.1 // indirect + github.com/eapache/go-resiliency v1.7.0 // indirect + github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect + github.com/eapache/queue v1.1.0 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.7.6 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.12.0 // indirect @@ -64,11 +80,11 @@ require ( github.com/tjfoc/gmsm v1.4.1 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/crypto v0.32.0 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/crypto v0.38.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect golang.org/x/time v0.8.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect google.golang.org/grpc v1.67.3 // indirect diff --git a/go.sum b/go.sum index fea502c..579db98 100644 --- a/go.sum +++ b/go.sum @@ -34,6 +34,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/IBM/sarama v1.45.2 h1:8m8LcMCu3REcwpa7fCP6v2fuPuzVwXDAM2DOv3CBrKw= +github.com/IBM/sarama v1.45.2/go.mod h1:ppaoTcVdGv186/z6MEKsMm70A5fwJfRTpstI37kVn3Y= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -125,6 +127,12 @@ 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/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= +github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= +github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -178,6 +186,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -206,9 +216,29 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -224,6 +254,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -253,6 +285,8 @@ github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc h1:Ak86L+yD github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -281,6 +315,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -305,12 +341,16 @@ github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqj github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +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/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= @@ -349,6 +389,7 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= @@ -356,6 +397,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -432,6 +475,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -452,6 +497,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -504,6 +551,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -527,6 +576,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -670,6 +721,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/pkg/kafka/consumer.go b/pkg/kafka/consumer.go new file mode 100644 index 0000000..5933674 --- /dev/null +++ b/pkg/kafka/consumer.go @@ -0,0 +1,97 @@ +package kafka + +import ( + "context" + + "github.com/IBM/sarama" +) + +type Consumer interface { + CreateConsumerGroup() error //创建消费者组 + GetConfig() *sarama.Config //获取配置 + Consume(ctx context.Context) error //消费信息 + Close() error //关闭消费者 +} + +// 实现 ConsumerGroupHandler 接口 +type Handler struct { + setupFunc func(sarama.ConsumerGroupSession) error + cleanupFunc func(sarama.ConsumerGroupSession) error + consumeclaimFunc func(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error +} + +func (c *Handler) Setup(session sarama.ConsumerGroupSession) error { + if c.setupFunc == nil { + return nil + } + return c.setupFunc(session) +} + +func (c *Handler) Cleanup(session sarama.ConsumerGroupSession) error { + if c.cleanupFunc == nil { + return nil + } + return c.cleanupFunc(session) +} + +func (c *Handler) ConsumeClaim(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error { + if c.consumeclaimFunc == nil { + return nil + } + return c.consumeclaimFunc(session, claim) +} + +func NewHandler(setupFunc, cleanupFunc func(sarama.ConsumerGroupSession) error, consumeclaimFunc func(sarama.ConsumerGroupSession, sarama.ConsumerGroupClaim) error) *Handler { + return &Handler{ + setupFunc: setupFunc, + cleanupFunc: cleanupFunc, + consumeclaimFunc: consumeclaimFunc, + } +} + +// 构造消费者结构体 +type ConsumerGroup struct { + config *sarama.Config //配置 + consumerGroup sarama.ConsumerGroup //消费者组 + host []string //kafka的地址 + group string //消费者组的名称 + topic []string //消费的主题 + handler *Handler //消费者组处理函数(用于实现sarama.ConsumerGroupHandler接口) +} + +func NewConsumerConfig(host []string, group string, topic []string, handler *Handler) Consumer { + config := sarama.NewConfig() + // 返回允许用户自己改配置 + return &ConsumerGroup{ + config: config, + handler: handler, + host: host, + group: group, + topic: topic, + } +} + +func (c *ConsumerGroup) GetConfig() *sarama.Config { + return c.config +} + +func (c *ConsumerGroup) CreateConsumerGroup() error { + group, err := sarama.NewConsumerGroup(c.host, c.group, c.config) + if err != nil { + return err + } + c.consumerGroup = group + return nil +} + +// 会一直阻塞消费直到出错或取消上下文 +func (c *ConsumerGroup) Consume(ctx context.Context) error { + if err := c.consumerGroup.Consume(ctx, c.topic, c.handler); err != nil { + return err + } + return nil +} + +func (c *ConsumerGroup) Close() error { + return c.consumerGroup.Close() +} diff --git a/pkg/kafka/producer.go b/pkg/kafka/producer.go new file mode 100644 index 0000000..af297cb --- /dev/null +++ b/pkg/kafka/producer.go @@ -0,0 +1,132 @@ +package kafka + +import ( + "github.com/IBM/sarama" +) + +type Producer interface { + CreateProducer() error //创建生产者 + GetConfig() *sarama.Config //获取配置 + GetSuccess() <-chan *sarama.ProducerMessage //异步获取成功消息 + GetError() <-chan *sarama.ProducerError //异步获取错误消息 + SendMessage(topic, key, value string) (int32, int64, error) //发送消息 + Close() error //关闭生产者 +} + +// 同步生成者 +type SyncProducer struct { + host []string //kafka的地址 + config *sarama.Config //配置 + producer sarama.SyncProducer //生产者 +} + +func NewSyncConfig(host []string) Producer { + config := sarama.NewConfig() + // 默认是false + config.Producer.Return.Successes = true // 必须设为 true + + // 返回允许用户自己改配置 + return &SyncProducer{ + host: host, + config: config, + } +} + +func (p *SyncProducer) GetConfig() *sarama.Config { + return p.config +} + +// 同步是直接返回的,写着部分只是为了和异步一致 +func (p *SyncProducer) GetSuccess() <-chan *sarama.ProducerMessage { + return nil +} + +func (p *SyncProducer) GetError() <-chan *sarama.ProducerError { + return nil +} + +func (p *SyncProducer) CreateProducer() error { + producer, err := sarama.NewSyncProducer(p.host, p.config) + if err != nil { + return err + } + + p.producer = producer + return nil +} + +func (p *SyncProducer) SendMessage(topic, key, value string) (int32, int64, error) { + msg := &sarama.ProducerMessage{ + Topic: topic, + Key: sarama.StringEncoder(key), + Value: sarama.StringEncoder(value), + } + + partition, offset, err := p.producer.SendMessage(msg) + if err != nil { + return -1, -1, err + } + return partition, offset, nil +} + +func (p *SyncProducer) Close() error { + return p.producer.Close() +} + +// 异步生成者 +type AsyncProducer struct { + host []string //kafka的地址 + config *sarama.Config //配置 + producer sarama.AsyncProducer //生产者 +} + +func NewAsyncConfig(host []string) Producer { + config := sarama.NewConfig() + // 默认是Waitforlocal + config.Producer.RequiredAcks = sarama.NoResponse + + // 返回允许用户自己改配置 + return &AsyncProducer{ + host: host, + config: config, + } +} + +func (p *AsyncProducer) GetConfig() *sarama.Config { + return p.config +} + +func (p *AsyncProducer) GetSuccess() <-chan *sarama.ProducerMessage { + return p.producer.Successes() +} + +func (p *AsyncProducer) GetError() <-chan *sarama.ProducerError { + return p.producer.Errors() +} + +func (p *AsyncProducer) CreateProducer() error { + producer, err := sarama.NewAsyncProducer(p.host, p.config) + if err != nil { + return err + } + + p.producer = producer + return nil +} + +func (p *AsyncProducer) SendMessage(topic, key, value string) (int32, int64, error) { + msg := &sarama.ProducerMessage{ + Topic: topic, + Key: sarama.StringEncoder(key), + Value: sarama.StringEncoder(value), + } + + p.producer.Input() <- msg + + //异步不能在这里查错 + return -1, -1, nil +} + +func (p *AsyncProducer) Close() error { + return p.producer.Close() +} From a54c1797856dee81e52c05602e6a378460af8a74 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Mon, 30 Jun 2025 14:04:24 +0800 Subject: [PATCH 02/19] =?UTF-8?q?:=20=E4=BF=AE=E6=94=B9=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=B8=8B=E7=94=9F=E4=BA=A7=E8=80=85=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=8C=E5=90=8C=E6=AD=A5=E5=92=8C=E5=BC=82=E6=AD=A5=E5=88=86?= =?UTF-8?q?=E6=88=90=E4=B8=A4=E4=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/kafka/producer.go | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/pkg/kafka/producer.go b/pkg/kafka/producer.go index af297cb..bad1123 100644 --- a/pkg/kafka/producer.go +++ b/pkg/kafka/producer.go @@ -4,15 +4,19 @@ import ( "github.com/IBM/sarama" ) -type Producer interface { +type Sync_producer interface { CreateProducer() error //创建生产者 GetConfig() *sarama.Config //获取配置 - GetSuccess() <-chan *sarama.ProducerMessage //异步获取成功消息 - GetError() <-chan *sarama.ProducerError //异步获取错误消息 SendMessage(topic, key, value string) (int32, int64, error) //发送消息 Close() error //关闭生产者 } +type Async_producer interface { + Sync_producer + GetSuccess() <-chan *sarama.ProducerMessage //异步获取成功消息 + GetError() <-chan *sarama.ProducerError //异步获取错误消息 +} + // 同步生成者 type SyncProducer struct { host []string //kafka的地址 @@ -20,7 +24,7 @@ type SyncProducer struct { producer sarama.SyncProducer //生产者 } -func NewSyncConfig(host []string) Producer { +func NewSyncConfig(host []string) Sync_producer { config := sarama.NewConfig() // 默认是false config.Producer.Return.Successes = true // 必须设为 true @@ -36,15 +40,6 @@ func (p *SyncProducer) GetConfig() *sarama.Config { return p.config } -// 同步是直接返回的,写着部分只是为了和异步一致 -func (p *SyncProducer) GetSuccess() <-chan *sarama.ProducerMessage { - return nil -} - -func (p *SyncProducer) GetError() <-chan *sarama.ProducerError { - return nil -} - func (p *SyncProducer) CreateProducer() error { producer, err := sarama.NewSyncProducer(p.host, p.config) if err != nil { @@ -78,9 +73,11 @@ type AsyncProducer struct { host []string //kafka的地址 config *sarama.Config //配置 producer sarama.AsyncProducer //生产者 + // successCh <-chan *sarama.ProducerMessage + // errorCh <-chan *sarama.ProducerError } -func NewAsyncConfig(host []string) Producer { +func NewAsyncConfig(host []string) Async_producer { config := sarama.NewConfig() // 默认是Waitforlocal config.Producer.RequiredAcks = sarama.NoResponse @@ -111,6 +108,8 @@ func (p *AsyncProducer) CreateProducer() error { } p.producer = producer + // p.successCh = p.producer.Successes() + // p.errorCh = p.producer.Errors() return nil } From c2e5642f059b909b770f3acb1658dd6043f4ca89 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Sat, 26 Jul 2025 15:29:10 +0800 Subject: [PATCH 03/19] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Etracer=E9=83=A8?= =?UTF-8?q?=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/kafka/{main.go => kafka.go} | 0 example/tracer/tracer.go | 38 +++++ go.mod | 23 ++- go.sum | 98 +++++++++++ pkg/tracer/tracer.go | 250 ++++++++++++++++++++++++++++ 5 files changed, 408 insertions(+), 1 deletion(-) rename example/kafka/{main.go => kafka.go} (100%) create mode 100644 example/tracer/tracer.go create mode 100644 pkg/tracer/tracer.go diff --git a/example/kafka/main.go b/example/kafka/kafka.go similarity index 100% rename from example/kafka/main.go rename to example/kafka/kafka.go diff --git a/example/tracer/tracer.go b/example/tracer/tracer.go new file mode 100644 index 0000000..182a826 --- /dev/null +++ b/example/tracer/tracer.go @@ -0,0 +1,38 @@ +package main + +import ( + "log" + + "github.com/muxi-Infra/muxi-micro/pkg/tracer" +) + +func Zipkin() { + config, err := tracer.NewZipkin("http://localhost:9411/api/v2/spans", "demo_service", "localhost:50052", 1) + if err != nil { + log.Fatal(err) + } + + // 客户端 + //conn, err := grpc.Dial( + // "localhost:50051", + // grpc.WithInsecure(), //禁用TLS + // grpc.WithUnaryInterceptor( + // grpcopentracing.UnaryClientInterceptor(), + // ), + //) + + // 服务端 + //s := grpc.NewServer( + // grpc_middleware.WithUnaryServerChain( + // config.ZipkinGrpc(), + // ), + //) + + if err := config.Close(); err != nil { + log.Fatal(err) + } +} + +func main() { + Zipkin() +} diff --git a/go.mod b/go.mod index d9ce4ce..b81e785 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,8 @@ require ( require ( github.com/IBM/sarama v1.45.2 // indirect + github.com/SkyAPM/go2sky v1.5.0 // indirect + github.com/SkyAPM/go2sky-plugins/gin/v3 v3.0.0-20230614023504-1db7dc6350fd // indirect github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 // indirect github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect github.com/alibabacloud-go/darabonba-array v0.1.0 // indirect @@ -43,11 +45,18 @@ require ( github.com/eapache/go-resiliency v1.7.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.7.7 // indirect + github.com/go-playground/locales v0.13.0 // indirect + github.com/go-playground/universal-translator v0.17.0 // indirect + github.com/go-playground/validator/v10 v10.4.1 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect @@ -58,9 +67,16 @@ require ( github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.0 // indirect + github.com/leodido/go-urn v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/opentracing-contrib/go-gin v0.0.0-20241203023905-a5650667207a // indirect + github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 // indirect + github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect @@ -78,6 +94,9 @@ require ( github.com/spf13/pflag v1.0.6 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect + github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect + github.com/uber/jaeger-lib v2.4.1+incompatible // indirect + github.com/ugorji/go/codec v1.1.7 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.38.0 // indirect @@ -90,5 +109,7 @@ require ( google.golang.org/grpc v1.67.3 // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + skywalking.apache.org/repo/goapi v0.0.0-20220401015832-2c9eee9481eb // indirect ) diff --git a/go.sum b/go.sum index 579db98..039ab47 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,11 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/IBM/sarama v1.45.2 h1:8m8LcMCu3REcwpa7fCP6v2fuPuzVwXDAM2DOv3CBrKw= github.com/IBM/sarama v1.45.2/go.mod h1:ppaoTcVdGv186/z6MEKsMm70A5fwJfRTpstI37kVn3Y= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/SkyAPM/go2sky v1.5.0 h1:TzhKL9IyVCegCUdcqRI7R7g+rQCYNnF6QAzp6IhDy08= +github.com/SkyAPM/go2sky v1.5.0/go.mod h1:cebzbFtq5oc9VrgJy0Sv7oePj/TjIlXPdj2ntHdCXd0= +github.com/SkyAPM/go2sky-plugins/gin/v3 v3.0.0-20230614023504-1db7dc6350fd h1:RqPYO+tjU234vT9ImS1mxZTfn54UOmXy+vjlxTnOBoQ= +github.com/SkyAPM/go2sky-plugins/gin/v3 v3.0.0-20230614023504-1db7dc6350fd/go.mod h1:NCrxU6oim+CCJ+3L/kL6O/JIScmRYhRsGn0wMiSCEbU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -102,6 +107,7 @@ github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmP github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= github.com/aliyun/credentials-go v1.4.3 h1:N3iHyvHRMyOwY1+0qBLSf3hb5JFiOujVSVuEpgeGttY= github.com/aliyun/credentials-go v1.4.3/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -111,6 +117,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -122,6 +129,9 @@ github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9 github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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= @@ -136,11 +146,20 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +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.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= +github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -150,10 +169,20 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -166,6 +195,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -199,6 +229,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -212,14 +243,21 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -244,6 +282,8 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -253,6 +293,7 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= @@ -266,6 +307,12 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -281,6 +328,17 @@ github.com/nacos-group/nacos-sdk-go/v2 v2.3.2 h1:9QB2nCJzT5wkTVlxNYl3XL/7+G6p2US github.com/nacos-group/nacos-sdk-go/v2 v2.3.2/go.mod h1:9FKXl6FqOiVmm72i8kADtbeK71egyG9y3uRDBg41tpQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/opentracing-contrib/go-gin v0.0.0-20241203023905-a5650667207a h1:knf+W5b/KLzKhne8yxsr+OlCM7P6xw4MDaF+EwcEiVU= +github.com/opentracing-contrib/go-gin v0.0.0-20241203023905-a5650667207a/go.mod h1:YmKG+/LVbHV0tn+c5fMWHDl3oYf2DpZk5SqVJmyGkl0= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 h1:uhcF5Jd7rP9DVEL10Siffyepr6SvlKbUsjH5JpNCRi8= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0/go.mod h1:+oCZ5GXXr7KPI/DNOQORPTq5AWHfALJj9c72b0+YsEY= +github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A= +github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc h1:Ak86L+yDSOzKFa7WM5bf5itSOo1e3Xh8bm5YCMUXIjQ= github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= @@ -317,6 +375,7 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -330,6 +389,7 @@ github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYl github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= @@ -358,10 +418,19 @@ github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSW github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= +github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= +github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= +github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -369,14 +438,17 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -421,6 +493,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -461,9 +534,11 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -491,6 +566,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -511,11 +587,13 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -539,6 +617,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -567,6 +647,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -599,6 +680,7 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -622,10 +704,13 @@ golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= @@ -676,14 +761,17 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A= google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -698,6 +786,10 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8= google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -712,6 +804,7 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= @@ -723,6 +816,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= @@ -731,6 +826,7 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXL gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -751,3 +847,5 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +skywalking.apache.org/repo/goapi v0.0.0-20220401015832-2c9eee9481eb h1:+PP2DpKFN/rEporLdPI4A7bPWQjwfARlUDKNhSab8iM= +skywalking.apache.org/repo/goapi v0.0.0-20220401015832-2c9eee9481eb/go.mod h1:uWwwvhcwe2MD/nJCg0c1EE/eL6KzaBosLHDfMFoEJ30= diff --git a/pkg/tracer/tracer.go b/pkg/tracer/tracer.go new file mode 100644 index 0000000..bc4d055 --- /dev/null +++ b/pkg/tracer/tracer.go @@ -0,0 +1,250 @@ +package tracer + +import ( + "context" + "errors" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "io" + "time" + + "github.com/SkyAPM/go2sky" + sgin "github.com/SkyAPM/go2sky-plugins/gin/v3" + sreporter "github.com/SkyAPM/go2sky/reporter" + "github.com/gin-gonic/gin" + "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing" + "github.com/opentracing-contrib/go-gin/ginhttp" + "github.com/opentracing/opentracing-go" + zipkinot "github.com/openzipkin-contrib/zipkin-go-opentracing" + "github.com/openzipkin/zipkin-go" + zreporter "github.com/openzipkin/zipkin-go/reporter" + zipkinreporter "github.com/openzipkin/zipkin-go/reporter/http" + jaegerconfig "github.com/uber/jaeger-client-go/config" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +type ZipkinConfig struct { + reporter zreporter.Reporter + tracer opentracing.Tracer +} + +func NewZipkin(zipkinAddr, service, host string, random float64) (*ZipkinConfig, error) { + if random > 1 || random < 0 { + return nil, errors.New("random number must be between 0 and 1") + } + // 初始化 zipkin tracer + report := zipkinreporter.NewReporter(zipkinAddr) + endpoint, err := zipkin.NewEndpoint(service, host) + if err != nil { + return nil, err + } + + // 设置取样概率 + sampler, err := zipkin.NewBoundarySampler(random, time.Now().UnixNano()) + if err != nil { + return nil, err + } + + tracer, err := zipkin.NewTracer( + report, + zipkin.WithLocalEndpoint(endpoint), + zipkin.WithSampler(sampler), + ) + if err != nil { + return nil, err + } + + t := zipkinot.Wrap(tracer) + + return &ZipkinConfig{ + reporter: report, + tracer: t, + }, nil +} + +func (z *ZipkinConfig) GrpcInterceptor() grpc.UnaryServerInterceptor { + opentracing.SetGlobalTracer(z.tracer) + return grpc_opentracing.UnaryServerInterceptor() +} + +func (z *ZipkinConfig) ClientInterceptor() grpc.UnaryClientInterceptor { + opentracing.SetGlobalTracer(z.tracer) + return grpc_opentracing.UnaryClientInterceptor() +} + +func (z *ZipkinConfig) GinMiddleware() gin.HandlerFunc { + return ginhttp.Middleware(z.tracer) +} + +func (z *ZipkinConfig) Close() error { + return z.reporter.Close() +} + +type JaegerConfig struct { + closer io.Closer + tracer opentracing.Tracer +} + +func NewJaeger(jaegerAddr, service string, random float64) (*JaegerConfig, error) { + var style string + if random > 1 || random < 0 { + return nil, errors.New("random number must be between 0 and 1") + } + if random == 1 || random == 0 { + style = "const" + } else { + style = "probabilistic" + } + cfg := jaegerconfig.Configuration{ + ServiceName: service, + Sampler: &jaegerconfig.SamplerConfig{ + Type: style, + Param: random, + }, + Reporter: &jaegerconfig.ReporterConfig{ + CollectorEndpoint: jaegerAddr, + //http://localhost:14268/api/traces + }, + } + + tracer, closer, err := cfg.NewTracer() + if err != nil { + return nil, err + } + + return &JaegerConfig{ + closer: closer, + tracer: tracer, + }, nil +} + +func (j *JaegerConfig) ServerInterceptor() grpc.UnaryServerInterceptor { + opentracing.SetGlobalTracer(j.tracer) + return grpc_opentracing.UnaryServerInterceptor() +} + +func (j *JaegerConfig) ClientInterceptor() grpc.UnaryClientInterceptor { + opentracing.SetGlobalTracer(j.tracer) + return grpc_opentracing.UnaryClientInterceptor() +} + +func (j *JaegerConfig) GinMiddleware() gin.HandlerFunc { + return ginhttp.Middleware(j.tracer) +} + +func (j *JaegerConfig) Close() error { + return j.closer.Close() +} + +type SkyWalkingConfig struct { + tracer *go2sky.Tracer + reporter go2sky.Reporter +} + +func NewSkyWalking(SkyWalkingAddr, service, instance string, random float64) (*SkyWalkingConfig, error) { + rep, err := sreporter.NewGRPCReporter(SkyWalkingAddr) + if err != nil { + return nil, err + } + + tracer, err := go2sky.NewTracer(service, go2sky.WithInstance(instance), go2sky.WithReporter(rep), go2sky.WithSampler(random)) + if err != nil { + return nil, err + } + + return &SkyWalkingConfig{ + tracer: tracer, + reporter: rep, + }, nil +} + +func (s *SkyWalkingConfig) ServerInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + md = metadata.New(nil) + } + + extractor := func(headerKey string) (string, error) { + if v := md.Get(headerKey); len(v) > 0 { // 使用动态传入的 headerKey + return v[0], nil + } + return "", nil + } + + span, ctx, err := s.tracer.CreateEntrySpan(ctx, info.FullMethod, extractor) + + if err != nil { + return handler(ctx, req) + } + + span.Tag(go2sky.TagHTTPMethod, "GRPC") + span.Tag(go2sky.TagURL, info.FullMethod) + + defer func() { + if r := recover(); r != nil { + err = status.Errorf(codes.Internal, "panic: %v", r) + span.Error(time.Now(), err.Error()) + span.Tag("error", "true") + } + if err != nil { + span.Error(time.Now(), err.Error()) + span.Tag("error", "true") + } + span.End() + }() + + resp, err = handler(ctx, req) + return resp, err + } +} + +func (s *SkyWalkingConfig) ClientInterceptor() grpc.UnaryClientInterceptor { + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + md, ok := metadata.FromOutgoingContext(ctx) + if !ok { + md = metadata.New(nil) + } + + extractor := func(headerKey, headerValue string) error { + md.Set(headerKey, headerValue) + ctx = metadata.NewOutgoingContext(ctx, md) + return nil + } + + span, err := s.tracer.CreateExitSpan(ctx, method, cc.Target(), extractor) + + if err != nil { + return invoker(ctx, method, req, reply, cc, opts...) + } + + span.Tag(go2sky.TagHTTPMethod, "GRPC") + span.Tag(go2sky.TagURL, method) + + defer func() { + if r := recover(); r != nil { + err = status.Errorf(codes.Internal, "panic: %v", r) + span.Error(time.Now(), err.Error()) + span.Tag("error", "true") + } + if err != nil { + span.Error(time.Now(), err.Error()) + span.Tag("error", "true") + } + span.End() + }() + + err = invoker(ctx, method, req, reply, cc, opts...) + return err + } +} + +func (s *SkyWalkingConfig) GinMiddleware(r *gin.Engine) gin.HandlerFunc { + return sgin.Middleware(r, s.tracer) +} + +func (s *SkyWalkingConfig) Close() error { + s.reporter.Close() + return nil +} From 8c4726e5ddb72d286b981f78dd32dd491fb12f10 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Tue, 29 Jul 2025 14:26:14 +0800 Subject: [PATCH 04/19] fix:tracer --- pkg/tracer/tracer.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pkg/tracer/tracer.go b/pkg/tracer/tracer.go index bc4d055..6435e5f 100644 --- a/pkg/tracer/tracer.go +++ b/pkg/tracer/tracer.go @@ -24,12 +24,19 @@ import ( "google.golang.org/grpc/metadata" ) +type Tracer interface { + ServerInterceptor() grpc.UnaryServerInterceptor + ClientInterceptor() grpc.UnaryClientInterceptor + GinMiddleware(r *gin.Engine) gin.HandlerFunc + Close() error +} + type ZipkinConfig struct { reporter zreporter.Reporter tracer opentracing.Tracer } -func NewZipkin(zipkinAddr, service, host string, random float64) (*ZipkinConfig, error) { +func NewZipkin(zipkinAddr, service, host string, random float64) (Tracer, error) { if random > 1 || random < 0 { return nil, errors.New("random number must be between 0 and 1") } @@ -63,7 +70,7 @@ func NewZipkin(zipkinAddr, service, host string, random float64) (*ZipkinConfig, }, nil } -func (z *ZipkinConfig) GrpcInterceptor() grpc.UnaryServerInterceptor { +func (z *ZipkinConfig) ServerInterceptor() grpc.UnaryServerInterceptor { opentracing.SetGlobalTracer(z.tracer) return grpc_opentracing.UnaryServerInterceptor() } @@ -73,7 +80,7 @@ func (z *ZipkinConfig) ClientInterceptor() grpc.UnaryClientInterceptor { return grpc_opentracing.UnaryClientInterceptor() } -func (z *ZipkinConfig) GinMiddleware() gin.HandlerFunc { +func (z *ZipkinConfig) GinMiddleware(_ *gin.Engine) gin.HandlerFunc { return ginhttp.Middleware(z.tracer) } @@ -86,7 +93,7 @@ type JaegerConfig struct { tracer opentracing.Tracer } -func NewJaeger(jaegerAddr, service string, random float64) (*JaegerConfig, error) { +func NewJaeger(jaegerAddr, service string, random float64) (Tracer, error) { var style string if random > 1 || random < 0 { return nil, errors.New("random number must be between 0 and 1") @@ -129,7 +136,7 @@ func (j *JaegerConfig) ClientInterceptor() grpc.UnaryClientInterceptor { return grpc_opentracing.UnaryClientInterceptor() } -func (j *JaegerConfig) GinMiddleware() gin.HandlerFunc { +func (j *JaegerConfig) GinMiddleware(_ *gin.Engine) gin.HandlerFunc { return ginhttp.Middleware(j.tracer) } @@ -142,7 +149,7 @@ type SkyWalkingConfig struct { reporter go2sky.Reporter } -func NewSkyWalking(SkyWalkingAddr, service, instance string, random float64) (*SkyWalkingConfig, error) { +func NewSkyWalking(SkyWalkingAddr, service, instance string, random float64) (Tracer, error) { rep, err := sreporter.NewGRPCReporter(SkyWalkingAddr) if err != nil { return nil, err From 6d6dfdb091024ab3cc2384c8100e91640695f706 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Fri, 1 Aug 2025 15:38:19 +0800 Subject: [PATCH 05/19] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Etracer=E7=9A=84?= =?UTF-8?q?test=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/tracer/tracer.go | 4 +++- pkg/tracer/tracer_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 pkg/tracer/tracer_test.go diff --git a/pkg/tracer/tracer.go b/pkg/tracer/tracer.go index 6435e5f..186a715 100644 --- a/pkg/tracer/tracer.go +++ b/pkg/tracer/tracer.go @@ -111,7 +111,6 @@ func NewJaeger(jaegerAddr, service string, random float64) (Tracer, error) { }, Reporter: &jaegerconfig.ReporterConfig{ CollectorEndpoint: jaegerAddr, - //http://localhost:14268/api/traces }, } @@ -150,6 +149,9 @@ type SkyWalkingConfig struct { } func NewSkyWalking(SkyWalkingAddr, service, instance string, random float64) (Tracer, error) { + if random > 1 || random < 0 { + return nil, errors.New("random number must be between 0 and 1") + } rep, err := sreporter.NewGRPCReporter(SkyWalkingAddr) if err != nil { return nil, err diff --git a/pkg/tracer/tracer_test.go b/pkg/tracer/tracer_test.go new file mode 100644 index 0000000..648b55a --- /dev/null +++ b/pkg/tracer/tracer_test.go @@ -0,0 +1,35 @@ +package tracer + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestRandomError(t *testing.T) { + t.Run("not correct random1", func(t *testing.T) { + _, err := NewZipkin( + "http://localhost:9411/api/v2/spans", + "demo_service", + "localhost:50051", + -1.0, + ) + assert.EqualError(t, err, "random number must be between 0 and 1") + }) + t.Run("not correct random2", func(t *testing.T) { + _, err := NewJaeger( + "http://localhost:14268/api/traces", + "demo_service", + 2.0, + ) + assert.EqualError(t, err, "random number must be between 0 and 1") + }) + t.Run("not correct random3", func(t *testing.T) { + _, err := NewSkyWalking( + "localhost:11800", + "demo_service", + "demo_instance", + 100, + ) + assert.EqualError(t, err, "random number must be between 0 and 1") + }) +} From ce7052dbfda9adc5461ed98c5fdff113685481e1 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Mon, 4 Aug 2025 16:18:58 +0800 Subject: [PATCH 06/19] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Etradcer?= =?UTF-8?q?=E7=9A=84test=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/tracer/tracer.go | 152 +++++++++++++++++++++++++++++++++------ go.mod | 25 +++---- go.sum | 28 ++++++++ pkg/kafka/producer.go | 12 ++-- 4 files changed, 175 insertions(+), 42 deletions(-) diff --git a/example/tracer/tracer.go b/example/tracer/tracer.go index 182a826..f6867f9 100644 --- a/example/tracer/tracer.go +++ b/example/tracer/tracer.go @@ -1,38 +1,146 @@ package main import ( - "log" - + "context" + "github.com/gin-gonic/gin" "github.com/muxi-Infra/muxi-micro/pkg/tracer" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/examples/helloworld/helloworld" + "log" + "net" ) -func Zipkin() { - config, err := tracer.NewZipkin("http://localhost:9411/api/v2/spans", "demo_service", "localhost:50052", 1) +// 简易的 HelloWorld 实现 +type server struct { + helloworld.UnimplementedGreeterServer +} + +func (s *server) SayHello(_ context.Context, in *helloworld.HelloRequest) (*helloworld.HelloReply, error) { + log.Printf("Received: %v", in.GetName()) + return &helloworld.HelloReply{Message: "Hello " + in.GetName()}, nil +} + +func GrpcServer() { + // Zipkin + config, err := tracer.NewZipkin( + "http://localhost:9411/api/v2/spans", + "demo_service", + "localhost:50051", + 1, + ) + + // Jaeger + //config , err := tracer.NewJaeger( + // "http://localhost:14268/api/traces", + // "demo_service", + // 1, + // ) + + // SkyWalking + //config , err := tracer.NewSkyWalking( + // "localhost:11800", + // "demo_service", + // "demo_instance", //实例名 + // 1 + // ) + if err != nil { log.Fatal(err) } + defer func() { + if err := config.Close(); err != nil { + log.Println(err) + } + }() + + s := grpc.NewServer( + grpc.ChainUnaryInterceptor( + config.ServerInterceptor(), + ), + ) + + helloworld.RegisterGreeterServer(s, &server{}) + + lis, err := net.Listen("tcp", "0.0.0.0:50051") + if err != nil { + log.Fatalf("failed to listen: %v", err) + } - // 客户端 - //conn, err := grpc.Dial( - // "localhost:50051", - // grpc.WithInsecure(), //禁用TLS - // grpc.WithUnaryInterceptor( - // grpcopentracing.UnaryClientInterceptor(), - // ), - //) - - // 服务端 - //s := grpc.NewServer( - // grpc_middleware.WithUnaryServerChain( - // config.ZipkinGrpc(), - // ), - //) - - if err := config.Close(); err != nil { + if err := s.Serve(lis); err != nil { + log.Fatalf("failed to serve: %v", err) + } +} + +func GrpcClient() { + // 同上 + config, err := tracer.NewZipkin( + "http://localhost:9411/api/v2/spans", + "demo_client", + "localhost:50051", + 1, + ) + if err != nil { + log.Fatal(err) + } + defer func() { + if err := config.Close(); err != nil { + log.Println(err) + } + }() + + conn, err := grpc.NewClient( + "localhost:50051", + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithChainUnaryInterceptor( + config.ClientInterceptor(), + ), + ) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + + c := helloworld.NewGreeterClient(conn) + + resp, err := c.SayHello(context.Background(), &helloworld.HelloRequest{Name: "MuXi"}) + if err != nil { + log.Fatalf("could not greet: %v", err) + } + log.Printf("Greeting: %s", resp.Message) +} + +func GinService() { + // 同上 + config, err := tracer.NewZipkin( + "http://localhost:9411/api/v2/spans", + "demo_gin", + "localhost:8081", + 1, + ) + if err != nil { log.Fatal(err) } + defer func() { + if err := config.Close(); err != nil { + log.Println(err) + } + }() + + r := gin.Default() + r.Use(config.GinMiddleware(r)) + + r.GET("/hello", func(c *gin.Context) { + c.JSON(200, gin.H{"message": "hello world"}) + }) + r.Run("0.0.0.0:8081") } func main() { - Zipkin() + // grpc服务端 + //GrpcServer() + // grpc客户端 + GrpcClient() + // gin + //GinService() } diff --git a/go.mod b/go.mod index b81e785..7852917 100644 --- a/go.mod +++ b/go.mod @@ -82,10 +82,10 @@ require ( github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.12.2 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.65.0 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -99,15 +99,16 @@ require ( github.com/ugorji/go/codec v1.1.7 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/crypto v0.38.0 // indirect - golang.org/x/net v0.40.0 // indirect - golang.org/x/sync v0.14.0 // indirect + golang.org/x/crypto v0.39.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sync v0.15.0 // indirect golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.25.0 // indirect - golang.org/x/time v0.8.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect - google.golang.org/grpc v1.67.3 // indirect - google.golang.org/protobuf v1.36.1 // indirect + golang.org/x/text v0.26.0 // indirect + golang.org/x/time v0.12.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/grpc v1.73.0 // indirect + google.golang.org/grpc/examples v0.0.0-20250724212526-9186ebd77437 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 039ab47..6da05c1 100644 --- a/go.sum +++ b/go.sum @@ -232,6 +232,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -357,28 +358,37 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= +github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -471,6 +481,8 @@ golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -552,6 +564,8 @@ golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -575,6 +589,8 @@ golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -659,11 +675,15 @@ golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -774,6 +794,8 @@ google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A= google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -792,6 +814,10 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8= google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= +google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc/examples v0.0.0-20250724212526-9186ebd77437 h1:iO8veeTfZD+IXBe1hTpGDNiqzyN5pJ9A93kcXLm84Lc= +google.golang.org/grpc/examples v0.0.0-20250724212526-9186ebd77437/go.mod h1:+i5rXBPtOU+ow1bg9RANESbDoFozEtcAT9ikIOTjm84= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -808,6 +834,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/kafka/producer.go b/pkg/kafka/producer.go index bad1123..73496e7 100644 --- a/pkg/kafka/producer.go +++ b/pkg/kafka/producer.go @@ -12,9 +12,9 @@ type Sync_producer interface { } type Async_producer interface { - Sync_producer - GetSuccess() <-chan *sarama.ProducerMessage //异步获取成功消息 - GetError() <-chan *sarama.ProducerError //异步获取错误消息 + Sync_producer + GetSuccess() <-chan *sarama.ProducerMessage //异步获取成功消息 + GetError() <-chan *sarama.ProducerError //异步获取错误消息 } // 同步生成者 @@ -73,13 +73,11 @@ type AsyncProducer struct { host []string //kafka的地址 config *sarama.Config //配置 producer sarama.AsyncProducer //生产者 - // successCh <-chan *sarama.ProducerMessage - // errorCh <-chan *sarama.ProducerError } func NewAsyncConfig(host []string) Async_producer { config := sarama.NewConfig() - // 默认是Waitforlocal + // 默认是 Waitforlocal config.Producer.RequiredAcks = sarama.NoResponse // 返回允许用户自己改配置 @@ -108,8 +106,6 @@ func (p *AsyncProducer) CreateProducer() error { } p.producer = producer - // p.successCh = p.producer.Successes() - // p.errorCh = p.producer.Errors() return nil } From 469d290b49fa5ca61ed6350588a467f8bc16252e Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Sun, 17 Aug 2025 20:46:51 +0800 Subject: [PATCH 07/19] =?UTF-8?q?:=20=E6=96=B0=E5=A2=9Esql=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=92=8Ccurd=E6=A8=A1=E6=9D=BF=EF=BC=8Ccurd=E7=9A=84?= =?UTF-8?q?=E4=B8=80=E7=82=B9=E7=82=B9=E7=82=B9=E7=82=B9=E7=82=B9=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 9 ++ go.sum | 20 +++ pkg/sql/cache.go | 55 +++++++ pkg/sql/sql.go | 86 +++++++++++ tool/curd/cobra/cobra.go | 68 +++++++++ tool/curd/main.go | 5 + tool/curd/model/model.go | 7 + tool/curd/parse/parsestruct.go | 134 +++++++++++++++++ tool/curd/template/example.go | 34 +++++ tool/curd/template/example_gen.go | 239 ++++++++++++++++++++++++++++++ tool/curd/template/var.go | 7 + tool/curd/template/var.tpl | 9 ++ tool/main.go | 35 +++++ 13 files changed, 708 insertions(+) create mode 100644 pkg/sql/cache.go create mode 100644 pkg/sql/sql.go create mode 100644 tool/curd/cobra/cobra.go create mode 100644 tool/curd/main.go create mode 100644 tool/curd/model/model.go create mode 100644 tool/curd/parse/parsestruct.go create mode 100644 tool/curd/template/example.go create mode 100644 tool/curd/template/example_gen.go create mode 100644 tool/curd/template/var.go create mode 100644 tool/curd/template/var.tpl create mode 100644 tool/main.go diff --git a/go.mod b/go.mod index 7852917..0fa0a63 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( ) require ( + filippo.io/edwards25519 v1.1.0 // indirect github.com/IBM/sarama v1.45.2 // indirect github.com/SkyAPM/go2sky v1.5.0 // indirect github.com/SkyAPM/go2sky-plugins/gin/v3 v3.0.0-20230614023504-1db7dc6350fd // indirect @@ -50,6 +51,8 @@ require ( github.com/go-playground/locales v0.13.0 // indirect github.com/go-playground/universal-translator v0.17.0 // indirect github.com/go-playground/validator/v10 v10.4.1 // indirect + github.com/go-redis/redis v6.15.9+incompatible // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -59,11 +62,14 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.0 // indirect @@ -91,6 +97,7 @@ require ( github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.12.0 // indirect github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/cobra v1.9.1 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect @@ -112,5 +119,7 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.6.0 // indirect + gorm.io/gorm v1.30.1 // indirect skywalking.apache.org/repo/goapi v0.0.0-20220401015832-2c9eee9481eb // indirect ) diff --git a/go.sum b/go.sum index 6da05c1..2a6d854 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -131,6 +133,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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= @@ -178,6 +181,10 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= @@ -267,6 +274,8 @@ github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= @@ -278,6 +287,10 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6 github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -389,6 +402,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -404,6 +418,8 @@ github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= @@ -865,6 +881,10 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= +gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= +gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= +gorm.io/gorm v1.30.1 h1:lSHg33jJTBxs2mgJRfRZeLDG+WZaHYCk3Wtfl6Ngzo4= +gorm.io/gorm v1.30.1/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/sql/cache.go b/pkg/sql/cache.go new file mode 100644 index 0000000..8caaa32 --- /dev/null +++ b/pkg/sql/cache.go @@ -0,0 +1,55 @@ +package sql + +import ( + "context" + "encoding/json" + "github.com/go-redis/redis" + "reflect" + "time" +) + +const CacheNotFound = redis.Nil + +type CacheExecute struct { + rdb *redis.Client + CacheTTL time.Duration + SetTTl time.Duration //写入缓存的允许最大时长 +} + +func ConnectCache(addr, password string, number int, TTL, TTL2 time.Duration) *CacheExecute { + rdb := redis.NewClient(&redis.Options{ + Addr: addr, + Password: password, + DB: number, + }) + + return &CacheExecute{ + rdb, + TTL, + TTL2, + } +} + +// cache 管理主键缓存 和 非主键向主键映射缓存 +func (c *CacheExecute) GetCache(cachestr string, ctx context.Context) (string, error) { + cache, err := c.rdb.WithContext(ctx).Get(cachestr).Result() + if err != nil { + return "", err + } + return cache, nil +} + +func (c *CacheExecute) SetCache(cachestr string, ctx context.Context, data any) error { + if reflect.ValueOf(data).Kind() != reflect.Ptr { + return ErrNonPointer + } + val, err := json.Marshal(data) + if err != nil { + return err + } + return c.rdb.WithContext(ctx).Set(cachestr, val, c.CacheTTL).Err() +} + +func (c *CacheExecute) DeleteCache(cachestr string, ctx context.Context) error { + return c.rdb.WithContext(ctx).Del(cachestr).Err() +} diff --git a/pkg/sql/sql.go b/pkg/sql/sql.go new file mode 100644 index 0000000..17f2299 --- /dev/null +++ b/pkg/sql/sql.go @@ -0,0 +1,86 @@ +package sql + +import ( + "context" + "errors" + "gorm.io/driver/mysql" + "gorm.io/gorm" + "gorm.io/gorm/logger" + "reflect" +) + +var ErrNonPointer = errors.New("data must be a pointer") + +func ConnectDB(dsn string, model any) (*gorm.DB, error) { + db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ + Logger: logger.Default.LogMode(logger.Error), + }) + if err != nil { + return nil, err + } + + if err := db.AutoMigrate(model); err != nil { + return nil, err + } + + return db, nil +} + +type Execute struct { + QueryOptions []func(db *gorm.DB) *gorm.DB + Model *gorm.DB +} + +func NewExecute(model any, db *gorm.DB) *Execute { + return &Execute{ + QueryOptions: nil, + Model: db.Model(model), + } +} + +// 拼接查询部分 +func (e *Execute) AddWhere(str string, val any) { + e.QueryOptions = append(e.QueryOptions, func(db *gorm.DB) *gorm.DB { + return db.Where(str, val) + }) +} + +func (e *Execute) Build(ctx context.Context) *gorm.DB { + query := e.Model.WithContext(ctx) + for _, opt := range e.QueryOptions { + query = opt(query) + } + e.QueryOptions = nil + return query +} + +// 可补充查询类型 + +// 执行部分 +func (e *Execute) Create(ctx context.Context, data any) error { + if reflect.ValueOf(data).Kind() != reflect.Ptr { + return ErrNonPointer + } + return e.Build(ctx).Create(data).Error +} + +func (e *Execute) Update(ctx context.Context, data any) error { + if reflect.ValueOf(data).Kind() != reflect.Ptr { + return ErrNonPointer + } + return e.Build(ctx).Save(data).Error +} + +func (e *Execute) Delete(ctx context.Context, data any) error { + if reflect.ValueOf(data).Kind() != reflect.Ptr { + return ErrNonPointer + } + return e.Build(ctx).Delete(data).Error +} + +func (e *Execute) Find(ctx context.Context, data any) error { + if reflect.ValueOf(data).Kind() != reflect.Ptr { + return ErrNonPointer + } + return e.Build(ctx).Find(data).Error +} diff --git a/tool/curd/cobra/cobra.go b/tool/curd/cobra/cobra.go new file mode 100644 index 0000000..76d8109 --- /dev/null +++ b/tool/curd/cobra/cobra.go @@ -0,0 +1,68 @@ +package cobra + +import ( + "github.com/spf13/cobra" + "os" + "path/filepath" + "text/template" +) + +func curdCobra() { + // curd 子命令 + var curdCmd = &cobra.Command{ + Use: "curd", + Short: "curd 自动生成工具", + Run: func(cmd *cobra.Command, args []string) { + pkg, err := cmd.Flags().GetString("package") + dir, err := cmd.Flags().GetString("dir") + if err != nil { + + } + err = CreateVar(pkg, dir) + if err != nil { + + } + }, + } + + curdCmd.Flags().String("package", "template", "生成文件的包名") + curdCmd.Flags().String("dir", ".", "文件生成目录") + + //_ = curdCmd.Execute() +} + +func CreateVar(pkg, dir string) error { + if err := os.MkdirAll(dir, 0755); err != nil { + return err + } + + tmplPath := filepath.Join("..", "template", "var.tpl") + tmplContent, err := os.ReadFile(tmplPath) + if err != nil { + return err + } + + t, err := template.New("var").Parse(string(tmplContent)) + if err != nil { + return err + } + + outputPath := filepath.Join(dir, "var.go") + file, err := os.Create(outputPath) + if err != nil { + return err + } + defer file.Close() + + data := struct { + PackageName string + }{ + PackageName: pkg, + } + + if err := t.Execute(file, data); err != nil { + return err + } + + return nil +} diff --git a/tool/curd/main.go b/tool/curd/main.go new file mode 100644 index 0000000..7905807 --- /dev/null +++ b/tool/curd/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + +} diff --git a/tool/curd/model/model.go b/tool/curd/model/model.go new file mode 100644 index 0000000..ec3f9b6 --- /dev/null +++ b/tool/curd/model/model.go @@ -0,0 +1,7 @@ +package model + +type User struct { + ID int `gorm:"primaryKey;autoIncrement"` + Username string `gorm:"size:50;primaryKey;"` + FirstName string `gorm:"size:30;index:idx_name"` +} diff --git a/tool/curd/parse/parsestruct.go b/tool/curd/parse/parsestruct.go new file mode 100644 index 0000000..9926b45 --- /dev/null +++ b/tool/curd/parse/parsestruct.go @@ -0,0 +1,134 @@ +package parse + +import ( + "errors" + "go/ast" + "go/parser" + "go/token" + "os" + "reflect" + "strings" +) + +var ( + ErrNoPrimaryKey = errors.New("you should create a primary key") + ErrManyPrimaryKey = errors.New("only one primary key need to be created") + ErrPrimaryKeyType = errors.New("primary key type should be int64") +) + +type FieldInfo struct { + Name string // 结构体字段名 + Type string // 字段类型 + Tag string // 原始标签 +} + +type StructInfo struct { + Name string // 结构体名 + Primary []FieldInfo + Index []FieldInfo +} + +func ParseStruct(filename string) (string, []string, error) { + filePath := "model/model.go" + content, err := os.ReadFile(filePath) + if err != nil { + return "", nil, err + } + + structInfos, err := parseFile(content) + if err != nil { + return "", nil, err + } + + if len(structInfos.Primary) == 0 { + return "", nil, ErrNoPrimaryKey + } + if len(structInfos.Primary) > 1 { + return "", nil, ErrManyPrimaryKey + } + if structInfos.Primary[0].Type != "int64" { + return "", nil, ErrPrimaryKeyType + } + + var index []string + for _, structInfo := range structInfos.Index { + if structInfo.Type == "unknown" { + continue + } + index = append(index, structInfo.Name) + } + + return structInfos.Primary[0].Name, index, nil +} + +// parseFile 解析Go文件中的结构体 +func parseFile(content []byte) (*StructInfo, error) { + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, "", content, parser.ParseComments) + if err != nil { + return nil, err + } + + var structInfos StructInfo + + ast.Inspect(f, func(n ast.Node) bool { + // 只处理type + typeSpec, ok := n.(*ast.TypeSpec) + if !ok { + return true + } + // 只处理struct + structType, ok := typeSpec.Type.(*ast.StructType) + if !ok { + return true + } + info := StructInfo{ + Name: typeSpec.Name.Name, + } + + for _, field := range structType.Fields.List { + // 跳过嵌入字段 + if len(field.Names) == 0 || field.Tag == nil { + continue + } + + fieldName := field.Names[0].Name + fieldType := getTypeName(field.Type) + + fieldInfo := FieldInfo{ + Name: fieldName, + Type: fieldType, + } + + tag := strings.Trim(field.Tag.Value, "`") + fieldInfo.Tag = getTagValue(tag, "gorm") + if fieldInfo.Tag != "" { + if isPrimaryKey := strings.Contains(fieldInfo.Tag, "primaryKey"); isPrimaryKey { + info.Primary = append(info.Primary, fieldInfo) + } + if isIndex := strings.Contains(fieldInfo.Tag, "index") || strings.Contains(fieldInfo.Tag, "unique"); isIndex { + info.Index = append(info.Index, fieldInfo) + } + } + } + + structInfos = info + return true + }) + + return &structInfos, nil +} + +func getTypeName(expr ast.Expr) string { + switch v := expr.(type) { + case *ast.Ident: + return v.Name + default: + return "unknown" + } +} + +func getTagValue(tag, key string) string { + tags := reflect.StructTag(tag) + return tags.Get(key) +} diff --git a/tool/curd/template/example.go b/tool/curd/template/example.go new file mode 100644 index 0000000..74a7cba --- /dev/null +++ b/tool/curd/template/example.go @@ -0,0 +1,34 @@ +package template + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/logger/zapx" + "github.com/muxi-Infra/muxi-micro/pkg/sql" + "time" +) + +var _ UserModels = (*ExtraUserExec)(nil) + +type UserModels interface { + UserModel + // ... +} + +type ExtraUserExec struct { + *UserExec +} + +func NewUserModels(DBdsn, redisAddr, redisPassword string, number int, ttl, ttl2 time.Duration) (UserModels, error) { + db, err := sql.ConnectDB(DBdsn, User{}) + if err != nil { + return nil, err + } + cache := sql.ConnectCache(redisAddr, redisPassword, number, ttl, ttl2) + l := zapx.NewDefaultZapLogger(logger.EnvTest, true, "./logs") + instance := NewUserModel(db, cache, l) + return &ExtraUserExec{ + instance, + }, nil +} + +// func (e *ExtraUserModel) diff --git a/tool/curd/template/example_gen.go b/tool/curd/template/example_gen.go new file mode 100644 index 0000000..379d046 --- /dev/null +++ b/tool/curd/template/example_gen.go @@ -0,0 +1,239 @@ +package template + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/sql" + "golang.org/x/sync/singleflight" + "gorm.io/gorm" +) + +const ( + cacheUserIdPrefix = "cache:user:id:" + cacheUserMobilePrefix = "cache:user:mobile:" + cacheUserUsernamePrefix = "cache:user:username:" +) + +var group singleflight.Group + +type UserModel interface { + Create(ctx context.Context, data *User) error + FindOne(ctx context.Context, id int64) (*User, error) + FindByMobile(ctx context.Context, mobile string) (*[]User, error) + FindByUsername(ctx context.Context, username string) (*[]User, error) + Update(ctx context.Context, data *User) error + Delete(ctx context.Context, id int64) error +} + +type User struct { + Id int64 `db:"id"` + Username string `db:"username"` + Password string `db:"password"` + Mobile string `db:"mobile"` +} + +type UserExec struct { + exec *sql.Execute + cacheExec *sql.CacheExecute + logger logger.Logger +} + +func NewUserModel(db *gorm.DB, cache *sql.CacheExecute, logger logger.Logger) *UserExec { + exec := sql.NewExecute(User{}, db) + return &UserExec{ + exec: exec, + cacheExec: cache, + logger: logger, + } +} + +func (u *UserExec) Create(ctx context.Context, data *User) error { + err := u.exec.Create(ctx, data) + if err != nil { + return err + } + go u.DelCache(ctx, data) + return nil +} + +func (u *UserExec) FindOne(ctx context.Context, id int64) (*User, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, id) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + datacache := u.Get(ctx, cachestr) + if datacache != nil { + return datacache, nil + } + var data User + u.exec.AddWhere("id = ?", id) + err := u.exec.Find(ctx, &data) + if err != nil { + return nil, err + } + go u.Set(cachestr, &data) + return &data, nil + }) + return result.(*User), err +} + +func (u *UserExec) FindByMobile(ctx context.Context, mobile string) (*[]User, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserMobilePrefix, mobile) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + datascache := u.GetMany(ctx, cacheval) + if datascache != nil { + return datascache, nil + } + var datas []User + u.exec.AddWhere("mobile = ?", mobile) + err = u.exec.Find(ctx, &datas) + if err != nil { + return nil, err + } + go u.SetMany(cachestr, &datas) + return &datas, nil + }) + return result.(*[]User), err +} + +func (u *UserExec) FindByUsername(ctx context.Context, username string) (*[]User, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, username) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + datascache := u.GetMany(ctx, cacheval) + if datascache != nil { + return datascache, nil + } + var datas []User + u.exec.AddWhere("username = ?", username) + err = u.exec.Find(ctx, &datas) + if err != nil { + return nil, err + } + go u.SetMany(cachestr, &datas) + return &datas, nil + }) + return result.(*[]User), err +} + +func (u *UserExec) Update(ctx context.Context, data *User) error { + u.exec.AddWhere("id = ?", data.Id) + err := u.exec.Update(ctx, data) + if err != nil { + return err + } + go u.DelCache(ctx, data) + return nil +} + +func (u *UserExec) Delete(ctx context.Context, id int64) error { + var data User + d, err := u.FindOne(ctx, id) + if err != nil { + return err + } + data = *d + err = u.exec.Delete(ctx, &data) + if err != nil { + return err + } + go u.DelCache(ctx, &data) + return nil +} + +// 序列化 +func UnMarshalJSON(s string, model *User) error { + return json.Unmarshal([]byte(s), model) +} + +func UnMarshalString(s string, model *[]int64) error { + return json.Unmarshal([]byte(s), model) +} + +// cache +func (u *UserExec) DelCache(ctx context.Context, model *User) { + err := u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserIdPrefix, model.Id), ctx) + if err != nil { + u.logger.Error("Primary key cache delete failure, id = "+fmt.Sprintf("%v", model.Id), err) + } + err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserMobilePrefix, model.Mobile), ctx) + if err != nil { + u.logger.Warn("Non-primary key cache delete failure: ", err) + } + err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserUsernamePrefix, model.Username), ctx) + if err != nil { + u.logger.Warn("Non-primary key cache delete failure: ", err) + } +} + +func (u *UserExec) Get(ctx context.Context, cachestr string) *User { + var data User + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + if err == nil { + err := UnMarshalJSON(cacheval, &data) + if err != nil { + u.logger.Warn("UnMarshal failure: ", err) + return nil + } + return &data + } + if !errors.Is(err, CacheNotFound) { + u.logger.Warn("Primary key cache get failure: ", err) + return nil + } + return nil +} + +func (u *UserExec) GetMany(ctx context.Context, cachestr string) *[]User { + var datas []User + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + if err == nil { + var key []int64 + err := UnMarshalString(cacheval, &key) + if err != nil { + u.logger.Warn("UnMarshal failure: ", err) + return nil + } + for _, c := range key { + data, err := u.FindOne(ctx, c) + if err != nil { + return nil + } + datas = append(datas, *data) + } + return &datas + } + if !errors.Is(err, CacheNotFound) { + u.logger.Warn("Primary key cache get failure: ", err) + return nil + } + return nil +} + +func (u *UserExec) Set(cachestr string, data *User) { + ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) + err := u.cacheExec.SetCache(cachestr, ctx, data) + if err != nil { + u.logger.Warn("Primary key cache set failure: ", err) + } + cancel() +} + +func (u *UserExec) SetMany(cachestr string, data *[]User) { + ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) + var key []int64 + for _, v := range *data { + key = append(key, v.Id) + err := u.cacheExec.SetCache(fmt.Sprintf("%s%v", cacheUserIdPrefix, v.Id), ctx, &v) + if err != nil { + u.logger.Warn("Primary key cache set failure: ", err) + } + } + err := u.cacheExec.SetCache(cachestr, ctx, &key) + if err != nil { + u.logger.Warn("Primary key cache set failure: ", err) + } + cancel() +} diff --git a/tool/curd/template/var.go b/tool/curd/template/var.go new file mode 100644 index 0000000..c82e087 --- /dev/null +++ b/tool/curd/template/var.go @@ -0,0 +1,7 @@ +package template + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/sql" +) + +const CacheNotFound = sql.CacheNotFound diff --git a/tool/curd/template/var.tpl b/tool/curd/template/var.tpl new file mode 100644 index 0000000..5613e90 --- /dev/null +++ b/tool/curd/template/var.tpl @@ -0,0 +1,9 @@ +{{- define "var" -}} +package {{.PackageName}} + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/sql" +) + +const CacheNotFound = sql.CacheNotFound +{{- end -}} \ No newline at end of file diff --git a/tool/main.go b/tool/main.go new file mode 100644 index 0000000..4232806 --- /dev/null +++ b/tool/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "context" + "fmt" + "github.com/muxi-Infra/muxi-micro/tool/curd/template" + "time" +) + +func main() { + ttl := 10 * time.Second + instance, err := template.NewUserModels( + "root:2388287244@tcp(112.126.68.22:3306)/library?parseTime=true&charset=utf8mb4&loc=Local", + "112.126.68.22:6379", + "lhx2388287244", + 0, + -1, + ttl, + ) + if err != nil { + fmt.Println(err) + } + user := template.User{ + Password: "666", + Username: "test777", + Mobile: "1145141919810", + } + err = instance.Create(context.Background(), &user) + if err != nil { + fmt.Println(err) + } + fmt.Println(user) + + select {} +} From 3f67138d5eef9620bddef6636fb300cef2d22d27 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Fri, 22 Aug 2025 16:02:45 +0800 Subject: [PATCH 08/19] =?UTF-8?q?:=20=E6=96=B0=E5=A2=9E=E8=87=AA?= =?UTF-8?q?=E5=8A=A8curd=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/sql/sql.go | 5 +- tool/curd/cobra/cobra.go | 74 ++++------ tool/curd/create/create.go | 123 ++++++++++++++++ .../example.go => example/UserModel.go} | 15 +- .../UserModel_gen.go} | 139 ++++++++++-------- tool/curd/example/model.go | 8 + tool/curd/{template => example}/var.go | 4 +- tool/curd/main.go | 5 - tool/curd/model/model.go | 7 - tool/curd/parse/parsestruct.go | 6 +- tool/curd/template/cache.tpl | 85 +++++++++++ tool/curd/template/db.tpl | 90 ++++++++++++ tool/curd/template/example.tpl | 37 +++++ tool/curd/template/header.tpl | 60 ++++++++ tool/curd/template/var.tpl | 2 + tool/main.go | 34 +---- 16 files changed, 537 insertions(+), 157 deletions(-) create mode 100644 tool/curd/create/create.go rename tool/curd/{template/example.go => example/UserModel.go} (68%) rename tool/curd/{template/example_gen.go => example/UserModel_gen.go} (63%) create mode 100644 tool/curd/example/model.go rename tool/curd/{template => example}/var.go (66%) delete mode 100644 tool/curd/main.go delete mode 100644 tool/curd/model/model.go create mode 100644 tool/curd/template/cache.tpl create mode 100644 tool/curd/template/db.tpl create mode 100644 tool/curd/template/example.tpl create mode 100644 tool/curd/template/header.tpl diff --git a/pkg/sql/sql.go b/pkg/sql/sql.go index 17f2299..c716e1c 100644 --- a/pkg/sql/sql.go +++ b/pkg/sql/sql.go @@ -9,7 +9,10 @@ import ( "reflect" ) -var ErrNonPointer = errors.New("data must be a pointer") +var ( + ErrNonPointer = errors.New("data must be a pointer") + DBNotFound = errors.New("this data is empty") +) func ConnectDB(dsn string, model any) (*gorm.DB, error) { db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ diff --git a/tool/curd/cobra/cobra.go b/tool/curd/cobra/cobra.go index 76d8109..f44894b 100644 --- a/tool/curd/cobra/cobra.go +++ b/tool/curd/cobra/cobra.go @@ -1,68 +1,58 @@ package cobra import ( + "fmt" + "github.com/muxi-Infra/muxi-micro/tool/curd/create" + "github.com/muxi-Infra/muxi-micro/tool/curd/parse" "github.com/spf13/cobra" "os" "path/filepath" - "text/template" ) -func curdCobra() { +func InitCurdCobra(parentCobra *cobra.Command) { // curd 子命令 var curdCmd = &cobra.Command{ Use: "curd", Short: "curd 自动生成工具", - Run: func(cmd *cobra.Command, args []string) { + Long: "在你想要生成 curd 文件的地方创建 model.go,内含可通过 gorm 自动迁移的结构体," + + "gorm 标签中 'primaryKey' 将被视为主键,主键和gorm标签中带有 'unique' 'index' 会自动生成查询", + RunE: func(cmd *cobra.Command, args []string) error { pkg, err := cmd.Flags().GetString("package") + if err != nil { + return err + } dir, err := cmd.Flags().GetString("dir") if err != nil { + return err + } + modelPath := filepath.Join(dir, "model.go") + if _, err := os.Stat(modelPath); err != nil { + return err } - err = CreateVar(pkg, dir) + table, index, err := parse.ParseStruct(modelPath) if err != nil { + return err + } + err = create.CreateExample_gen(pkg, dir, table, index) + if err != nil { + return err + } + err = create.CreateExample(pkg, dir, table) + if err != nil { + return err + } + err = create.CreateVar(pkg, dir) + if err != nil { + fmt.Println(err) } + return nil }, } curdCmd.Flags().String("package", "template", "生成文件的包名") - curdCmd.Flags().String("dir", ".", "文件生成目录") - - //_ = curdCmd.Execute() -} - -func CreateVar(pkg, dir string) error { - if err := os.MkdirAll(dir, 0755); err != nil { - return err - } - - tmplPath := filepath.Join("..", "template", "var.tpl") - tmplContent, err := os.ReadFile(tmplPath) - if err != nil { - return err - } - - t, err := template.New("var").Parse(string(tmplContent)) - if err != nil { - return err - } - - outputPath := filepath.Join(dir, "var.go") - file, err := os.Create(outputPath) - if err != nil { - return err - } - defer file.Close() - - data := struct { - PackageName string - }{ - PackageName: pkg, - } - - if err := t.Execute(file, data); err != nil { - return err - } + curdCmd.Flags().String("dir", ".", "model文件以及文件生成目录") - return nil + parentCobra.AddCommand(curdCmd) } diff --git a/tool/curd/create/create.go b/tool/curd/create/create.go new file mode 100644 index 0000000..7583677 --- /dev/null +++ b/tool/curd/create/create.go @@ -0,0 +1,123 @@ +package create + +import ( + "os" + "path/filepath" + "strings" + "text/template" + "unicode" +) + +func safeFilename(tableName string) string { + return strings.Map(func(r rune) rune { + if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' || r == '-' { + return r + } + return '_' + }, tableName) +} + +func CreateVar(pkg, dir string) error { + tmplPath := filepath.Join("curd", "template", "var.tpl") + + t, err := template.New("var").ParseFiles(tmplPath) + if err != nil { + return err + } + + outputPath := filepath.Join(dir, "var.go") + file, err := os.Create(outputPath) + if err != nil { + return err + } + + defer file.Close() + + data := struct { + PackageName string + }{ + PackageName: pkg, + } + + if err := t.ExecuteTemplate(file, "var", data); err != nil { + return err + } + + return nil +} + +func CreateExample(pkg, dir, table string) error { + tmplPath := filepath.Join("curd", "template", "example.tpl") + + t, err := template.New("example").ParseFiles(tmplPath) + if err != nil { + return err + } + + outputPath := filepath.Join(dir, safeFilename(table)+"Model.go") + file, err := os.Create(outputPath) + if err != nil { + return err + } + + defer file.Close() + + data := struct { + PackageName string + ModelName string + }{ + PackageName: pkg, + ModelName: table, + } + + if err := t.ExecuteTemplate(file, "example", data); err != nil { + return err + } + + return nil +} + +func CreateExample_gen(pkg, dir, table string, fields []string) error { + tmplPath := []string{ + filepath.Join("curd", "template", "header.tpl"), + filepath.Join("curd", "template", "cache.tpl"), + filepath.Join("curd", "template", "db.tpl"), + } + + t, err := template.New("header").ParseFiles(tmplPath...) + if err != nil { + return err + } + + outputPath := filepath.Join(dir, safeFilename(table)+"Model_gen.go") + file, err := os.Create(outputPath) + if err != nil { + return err + } + + defer file.Close() + + data := struct { + PackageName string + ModelName string + Fields []string + NotPrs []string + Pr string + }{ + PackageName: pkg, + ModelName: table, + Fields: fields, + NotPrs: fields[:len(fields)-1], + Pr: fields[len(fields)-1], + } + + if err := t.ExecuteTemplate(file, "header", data); err != nil { + return err + } + + // 设置为只读权限 + if err := file.Chmod(0444); err != nil { + return err + } + return nil +} diff --git a/tool/curd/template/example.go b/tool/curd/example/UserModel.go similarity index 68% rename from tool/curd/template/example.go rename to tool/curd/example/UserModel.go index 74a7cba..7d6952c 100644 --- a/tool/curd/template/example.go +++ b/tool/curd/example/UserModel.go @@ -1,8 +1,7 @@ -package template +package example import ( "github.com/muxi-Infra/muxi-micro/pkg/logger" - "github.com/muxi-Infra/muxi-micro/pkg/logger/zapx" "github.com/muxi-Infra/muxi-micro/pkg/sql" "time" ) @@ -11,24 +10,26 @@ var _ UserModels = (*ExtraUserExec)(nil) type UserModels interface { UserModel - // ... + // 可以在这里添加额外的方法接口 } type ExtraUserExec struct { *UserExec } -func NewUserModels(DBdsn, redisAddr, redisPassword string, number int, ttl, ttl2 time.Duration) (UserModels, error) { +func NewUserModels(DBdsn, redisAddr, redisPassword string, number int, ttlForCache, ttlForSet time.Duration, l logger.Logger) (UserModels, error) { db, err := sql.ConnectDB(DBdsn, User{}) if err != nil { return nil, err } - cache := sql.ConnectCache(redisAddr, redisPassword, number, ttl, ttl2) - l := zapx.NewDefaultZapLogger(logger.EnvTest, true, "./logs") + cache := sql.ConnectCache(redisAddr, redisPassword, number, ttlForCache, ttlForSet) + instance := NewUserModel(db, cache, l) + return &ExtraUserExec{ instance, }, nil } -// func (e *ExtraUserModel) +// 可以在这里添加额外的方法实现 +// func (e *ExtraUserExec) ... \ No newline at end of file diff --git a/tool/curd/template/example_gen.go b/tool/curd/example/UserModel_gen.go similarity index 63% rename from tool/curd/template/example_gen.go rename to tool/curd/example/UserModel_gen.go index 379d046..eed8a49 100644 --- a/tool/curd/template/example_gen.go +++ b/tool/curd/example/UserModel_gen.go @@ -1,53 +1,55 @@ -package template +package example import ( - "context" - "encoding/json" - "errors" - "fmt" - "github.com/muxi-Infra/muxi-micro/pkg/logger" - "github.com/muxi-Infra/muxi-micro/pkg/sql" - "golang.org/x/sync/singleflight" - "gorm.io/gorm" + "context" + "encoding/json" + "errors" + "fmt" + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/sql" + "golang.org/x/sync/singleflight" + "gorm.io/gorm" ) const ( - cacheUserIdPrefix = "cache:user:id:" - cacheUserMobilePrefix = "cache:user:mobile:" - cacheUserUsernamePrefix = "cache:user:username:" + cacheUserUsernamePrefix = "cache:User:Username:" + cacheUserMobilePrefix = "cache:User:Mobile:" + cacheUserIdPrefix = "cache:User:Id:" ) var group singleflight.Group type UserModel interface { - Create(ctx context.Context, data *User) error - FindOne(ctx context.Context, id int64) (*User, error) - FindByMobile(ctx context.Context, mobile string) (*[]User, error) - FindByUsername(ctx context.Context, username string) (*[]User, error) - Update(ctx context.Context, data *User) error - Delete(ctx context.Context, id int64) error -} - -type User struct { - Id int64 `db:"id"` - Username string `db:"username"` - Password string `db:"password"` - Mobile string `db:"mobile"` + Create(ctx context.Context, data *User) error + FindOne(ctx context.Context, id int64) (*User, error) + FindByUsername(ctx context.Context, Username string) (*[]User, error) + FindByMobile(ctx context.Context, Mobile string) (*[]User, error) + Update(ctx context.Context, data *User) error + Delete(ctx context.Context, id int64) error } type UserExec struct { - exec *sql.Execute - cacheExec *sql.CacheExecute - logger logger.Logger + exec *sql.Execute + cacheExec *sql.CacheExecute + logger logger.Logger } func NewUserModel(db *gorm.DB, cache *sql.CacheExecute, logger logger.Logger) *UserExec { - exec := sql.NewExecute(User{}, db) - return &UserExec{ - exec: exec, - cacheExec: cache, - logger: logger, - } + exec := sql.NewExecute(User{}, db) + return &UserExec{ + exec: exec, + cacheExec: cache, + logger: logger, + } +} + +// 序列化 +func UnMarshalJSON(s string, model *User) error { + return json.Unmarshal([]byte(s), model) +} + +func UnMarshalString(s string, model *[]int64) error { + return json.Unmarshal([]byte(s), model) } func (u *UserExec) Create(ctx context.Context, data *User) error { @@ -72,14 +74,20 @@ func (u *UserExec) FindOne(ctx context.Context, id int64) (*User, error) { if err != nil { return nil, err } + if data.Id == 0 { + return nil, DBNotFound + } go u.Set(cachestr, &data) return &data, nil }) + if result == nil { + return nil, err + } return result.(*User), err } -func (u *UserExec) FindByMobile(ctx context.Context, mobile string) (*[]User, error) { - cachestr := fmt.Sprintf("%s%v", cacheUserMobilePrefix, mobile) +func (u *UserExec) FindByUsername(ctx context.Context, Username string) (*[]User, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, Username) result, err, _ := group.Do(cachestr, func() (interface{}, error) { cacheval, err := u.cacheExec.GetCache(cachestr, ctx) datascache := u.GetMany(ctx, cacheval) @@ -87,19 +95,25 @@ func (u *UserExec) FindByMobile(ctx context.Context, mobile string) (*[]User, er return datascache, nil } var datas []User - u.exec.AddWhere("mobile = ?", mobile) + u.exec.AddWhere("Username = ?", Username) err = u.exec.Find(ctx, &datas) if err != nil { return nil, err } + if len(datas) == 0 { + return nil, DBNotFound + } go u.SetMany(cachestr, &datas) return &datas, nil }) + if result == nil { + return nil, err + } return result.(*[]User), err } -func (u *UserExec) FindByUsername(ctx context.Context, username string) (*[]User, error) { - cachestr := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, username) +func (u *UserExec) FindByMobile(ctx context.Context, Mobile string) (*[]User, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserMobilePrefix, Mobile) result, err, _ := group.Do(cachestr, func() (interface{}, error) { cacheval, err := u.cacheExec.GetCache(cachestr, ctx) datascache := u.GetMany(ctx, cacheval) @@ -107,14 +121,20 @@ func (u *UserExec) FindByUsername(ctx context.Context, username string) (*[]User return datascache, nil } var datas []User - u.exec.AddWhere("username = ?", username) + u.exec.AddWhere("Mobile = ?", Mobile) err = u.exec.Find(ctx, &datas) if err != nil { return nil, err } + if len(datas) == 0 { + return nil, DBNotFound + } go u.SetMany(cachestr, &datas) return &datas, nil }) + if result == nil { + return nil, err + } return result.(*[]User), err } @@ -143,29 +163,20 @@ func (u *UserExec) Delete(ctx context.Context, id int64) error { return nil } -// 序列化 -func UnMarshalJSON(s string, model *User) error { - return json.Unmarshal([]byte(s), model) -} - -func UnMarshalString(s string, model *[]int64) error { - return json.Unmarshal([]byte(s), model) -} - // cache func (u *UserExec) DelCache(ctx context.Context, model *User) { err := u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserIdPrefix, model.Id), ctx) if err != nil { - u.logger.Error("Primary key cache delete failure, id = "+fmt.Sprintf("%v", model.Id), err) - } - err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserMobilePrefix, model.Mobile), ctx) - if err != nil { - u.logger.Warn("Non-primary key cache delete failure: ", err) - } - err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserUsernamePrefix, model.Username), ctx) - if err != nil { - u.logger.Warn("Non-primary key cache delete failure: ", err) + u.logger.Error("Primary key cache delete failure", err) } + err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserUsernamePrefix, model.Username), ctx) + if err != nil { + u.logger.Warn("Not-primary key cache delete failure", err) + } + err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserMobilePrefix, model.Mobile), ctx) + if err != nil { + u.logger.Warn("Not-primary key cache delete failure", err) + } } func (u *UserExec) Get(ctx context.Context, cachestr string) *User { @@ -206,7 +217,7 @@ func (u *UserExec) GetMany(ctx context.Context, cachestr string) *[]User { return &datas } if !errors.Is(err, CacheNotFound) { - u.logger.Warn("Primary key cache get failure: ", err) + u.logger.Warn("Not-primary key cache get failure: ", err) return nil } return nil @@ -226,14 +237,12 @@ func (u *UserExec) SetMany(cachestr string, data *[]User) { var key []int64 for _, v := range *data { key = append(key, v.Id) - err := u.cacheExec.SetCache(fmt.Sprintf("%s%v", cacheUserIdPrefix, v.Id), ctx, &v) - if err != nil { - u.logger.Warn("Primary key cache set failure: ", err) - } + cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, v.Id) + u.Set(cachestr, &v) } err := u.cacheExec.SetCache(cachestr, ctx, &key) if err != nil { - u.logger.Warn("Primary key cache set failure: ", err) + u.logger.Warn("Not-primary key cache set failure: ", err) } cancel() -} +} \ No newline at end of file diff --git a/tool/curd/example/model.go b/tool/curd/example/model.go new file mode 100644 index 0000000..9ba7034 --- /dev/null +++ b/tool/curd/example/model.go @@ -0,0 +1,8 @@ +package example + +type User struct { + Id int64 `gorm:"primaryKey;autoIncrement"` + Username string `gorm:"size:50;unique;"` + Password string `db:"password"` + Mobile string `gorm:"size:30;index:idx_name"` +} diff --git a/tool/curd/template/var.go b/tool/curd/example/var.go similarity index 66% rename from tool/curd/template/var.go rename to tool/curd/example/var.go index c82e087..3412d7f 100644 --- a/tool/curd/template/var.go +++ b/tool/curd/example/var.go @@ -1,7 +1,9 @@ -package template +package example import ( "github.com/muxi-Infra/muxi-micro/pkg/sql" ) const CacheNotFound = sql.CacheNotFound + +var DBNotFound = sql.DBNotFound \ No newline at end of file diff --git a/tool/curd/main.go b/tool/curd/main.go deleted file mode 100644 index 7905807..0000000 --- a/tool/curd/main.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func main() { - -} diff --git a/tool/curd/model/model.go b/tool/curd/model/model.go deleted file mode 100644 index ec3f9b6..0000000 --- a/tool/curd/model/model.go +++ /dev/null @@ -1,7 +0,0 @@ -package model - -type User struct { - ID int `gorm:"primaryKey;autoIncrement"` - Username string `gorm:"size:50;primaryKey;"` - FirstName string `gorm:"size:30;index:idx_name"` -} diff --git a/tool/curd/parse/parsestruct.go b/tool/curd/parse/parsestruct.go index 9926b45..ad9d0d3 100644 --- a/tool/curd/parse/parsestruct.go +++ b/tool/curd/parse/parsestruct.go @@ -28,8 +28,7 @@ type StructInfo struct { Index []FieldInfo } -func ParseStruct(filename string) (string, []string, error) { - filePath := "model/model.go" +func ParseStruct(filePath string) (string, []string, error) { content, err := os.ReadFile(filePath) if err != nil { return "", nil, err @@ -58,7 +57,8 @@ func ParseStruct(filename string) (string, []string, error) { index = append(index, structInfo.Name) } - return structInfos.Primary[0].Name, index, nil + index = append(index, structInfos.Primary[0].Name) + return structInfos.Name, index, nil } // parseFile 解析Go文件中的结构体 diff --git a/tool/curd/template/cache.tpl b/tool/curd/template/cache.tpl new file mode 100644 index 0000000..f4db372 --- /dev/null +++ b/tool/curd/template/cache.tpl @@ -0,0 +1,85 @@ +{{- define "cache" -}} +// cache +func (u *{{.ModelName}}Exec) DelCache(ctx context.Context, model *{{.ModelName}}) { + err := u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cache{{.ModelName}}{{.Pr}}Prefix, model.{{.Pr}}), ctx) + if err != nil { + u.logger.Error("Primary key cache delete failure", err) + } + {{- $outer := . -}} + {{- range $notpr := .NotPrs}} + err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cache{{$outer.ModelName}}{{$notpr}}Prefix, model.{{$notpr}}), ctx) + if err != nil { + u.logger.Warn("Not-primary key cache delete failure", err) + } + {{- end}} +} + +func (u *{{.ModelName}}Exec) Get(ctx context.Context, cachestr string) *{{.ModelName}} { + var data {{.ModelName}} + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + if err == nil { + err := UnMarshalJSON(cacheval, &data) + if err != nil { + u.logger.Warn("UnMarshal failure: ", err) + return nil + } + return &data + } + if !errors.Is(err, CacheNotFound) { + u.logger.Warn("Primary key cache get failure: ", err) + return nil + } + return nil +} + +func (u *{{.ModelName}}Exec) GetMany(ctx context.Context, cachestr string) *[]{{.ModelName}} { + var datas []{{.ModelName}} + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + if err == nil { + var key []int64 + err := UnMarshalString(cacheval, &key) + if err != nil { + u.logger.Warn("UnMarshal failure: ", err) + return nil + } + for _, c := range key { + data, err := u.FindOne(ctx, c) + if err != nil { + return nil + } + datas = append(datas, *data) + } + return &datas + } + if !errors.Is(err, CacheNotFound) { + u.logger.Warn("Not-primary key cache get failure: ", err) + return nil + } + return nil +} + +func (u *{{.ModelName}}Exec) Set(cachestr string, data *{{.ModelName}}) { + ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) + err := u.cacheExec.SetCache(cachestr, ctx, data) + if err != nil { + u.logger.Warn("Primary key cache set failure: ", err) + } + cancel() +} + +func (u *{{.ModelName}}Exec) SetMany(cachestr string, data *[]{{.ModelName}}) { + ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) + var key []int64 + for _, v := range *data { + key = append(key, v.{{.Pr}}) + cachestr := fmt.Sprintf("%s%v", cache{{.ModelName}}IdPrefix, v.{{.Pr}}) + u.Set(cachestr, &v) + } + err := u.cacheExec.SetCache(cachestr, ctx, &key) + if err != nil { + u.logger.Warn("Not-primary key cache set failure: ", err) + } + cancel() +} + +{{- end -}} \ No newline at end of file diff --git a/tool/curd/template/db.tpl b/tool/curd/template/db.tpl new file mode 100644 index 0000000..1881c2d --- /dev/null +++ b/tool/curd/template/db.tpl @@ -0,0 +1,90 @@ +{{- define "db" -}} +func (u *{{.ModelName}}Exec) Create(ctx context.Context, data *{{.ModelName}}) error { + err := u.exec.Create(ctx, data) + if err != nil { + return err + } + go u.DelCache(ctx, data) + return nil +} + +func (u *{{.ModelName}}Exec) FindOne(ctx context.Context, id int64) (*{{.ModelName}}, error) { + cachestr := fmt.Sprintf("%s%v", cache{{.ModelName}}{{.Pr}}Prefix, id) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + datacache := u.Get(ctx, cachestr) + if datacache != nil { + return datacache, nil + } + var data {{.ModelName}} + u.exec.AddWhere("id = ?", id) + err := u.exec.Find(ctx, &data) + if err != nil { + return nil, err + } + if data.{{.Pr}} == 0 { + return nil, DBNotFound + } + go u.Set(cachestr, &data) + return &data, nil + }) + if result == nil { + return nil, err + } + return result.(*{{.ModelName}}), err +} + +{{- $outer := . -}} +{{- range $notpr := .NotPrs}} + +func (u *{{$outer.ModelName}}Exec) FindBy{{$notpr}}(ctx context.Context, {{$notpr}} string) (*[]{{$outer.ModelName}}, error) { + cachestr := fmt.Sprintf("%s%v", cache{{$outer.ModelName}}{{$notpr}}Prefix, {{$notpr}}) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + datascache := u.GetMany(ctx, cacheval) + if datascache != nil { + return datascache, nil + } + var datas []{{$outer.ModelName}} + u.exec.AddWhere("{{$notpr}} = ?", {{$notpr}}) + err = u.exec.Find(ctx, &datas) + if err != nil { + return nil, err + } + if len(datas) == 0 { + return nil, DBNotFound + } + go u.SetMany(cachestr, &datas) + return &datas, nil + }) + if result == nil { + return nil, err + } + return result.(*[]{{$outer.ModelName}}), err +} +{{- end}} + +func (u *{{.ModelName}}Exec) Update(ctx context.Context, data *{{.ModelName}}) error { + u.exec.AddWhere("id = ?", data.{{.Pr}}) + err := u.exec.Update(ctx, data) + if err != nil { + return err + } + go u.DelCache(ctx, data) + return nil +} + +func (u *{{.ModelName}}Exec) Delete(ctx context.Context, id int64) error { + var data {{.ModelName}} + d, err := u.FindOne(ctx, id) + if err != nil { + return err + } + data = *d + err = u.exec.Delete(ctx, &data) + if err != nil { + return err + } + go u.DelCache(ctx, &data) + return nil +} +{{- end -}} \ No newline at end of file diff --git a/tool/curd/template/example.tpl b/tool/curd/template/example.tpl new file mode 100644 index 0000000..491980d --- /dev/null +++ b/tool/curd/template/example.tpl @@ -0,0 +1,37 @@ +{{- define "example" -}} +package {{.PackageName}} + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/sql" + "time" +) + +var _ {{.ModelName}}Models = (*Extra{{.ModelName}}Exec)(nil) + +type {{.ModelName}}Models interface { + {{.ModelName}}Model + // 可以在这里添加额外的方法接口 +} + +type Extra{{.ModelName}}Exec struct { + *{{.ModelName}}Exec +} + +func New{{.ModelName}}Models(DBdsn, redisAddr, redisPassword string, number int, ttlForCache, ttlForSet time.Duration, l logger.Logger) ({{.ModelName}}Models, error) { + db, err := sql.ConnectDB(DBdsn, {{.ModelName}}{}) + if err != nil { + return nil, err + } + cache := sql.ConnectCache(redisAddr, redisPassword, number, ttlForCache, ttlForSet) + + instance := New{{.ModelName}}Model(db, cache, l) + + return &Extra{{.ModelName}}Exec{ + instance, + }, nil +} + +// 可以在这里添加额外的方法实现 +// func (e *Extra{{.ModelName}}Exec) ... +{{- end -}} \ No newline at end of file diff --git a/tool/curd/template/header.tpl b/tool/curd/template/header.tpl new file mode 100644 index 0000000..c4c42e7 --- /dev/null +++ b/tool/curd/template/header.tpl @@ -0,0 +1,60 @@ +{{- define "header" -}} +package {{.PackageName}} + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/sql" + "golang.org/x/sync/singleflight" + "gorm.io/gorm" +) + +const ( + {{- range $field := .Fields}} + cache{{$.ModelName}}{{$field}}Prefix = "cache:{{$.ModelName}}:{{$field}}:" + {{- end}} +) + +var group singleflight.Group + +type {{.ModelName}}Model interface { + Create(ctx context.Context, data *{{.ModelName}}) error + FindOne(ctx context.Context, id int64) (*{{.ModelName}}, error) + {{- range $notPr := .NotPrs}} + FindBy{{$notPr}}(ctx context.Context, {{$notPr}} string) (*[]{{$.ModelName}}, error) + {{- end}} + Update(ctx context.Context, data *{{.ModelName}}) error + Delete(ctx context.Context, id int64) error +} + +type {{.ModelName}}Exec struct { + exec *sql.Execute + cacheExec *sql.CacheExecute + logger logger.Logger +} + +func New{{.ModelName}}Model(db *gorm.DB, cache *sql.CacheExecute, logger logger.Logger) *{{.ModelName}}Exec { + exec := sql.NewExecute({{.ModelName}}{}, db) + return &{{.ModelName}}Exec{ + exec: exec, + cacheExec: cache, + logger: logger, + } +} + +// 序列化 +func UnMarshalJSON(s string, model *{{.ModelName}}) error { + return json.Unmarshal([]byte(s), model) +} + +func UnMarshalString(s string, model *[]int64) error { + return json.Unmarshal([]byte(s), model) +} + +{{template "db" $}} + +{{template "cache" $}} +{{- end -}} \ No newline at end of file diff --git a/tool/curd/template/var.tpl b/tool/curd/template/var.tpl index 5613e90..59f2ea7 100644 --- a/tool/curd/template/var.tpl +++ b/tool/curd/template/var.tpl @@ -6,4 +6,6 @@ import ( ) const CacheNotFound = sql.CacheNotFound + +var DBNotFound = sql.DBNotFound {{- end -}} \ No newline at end of file diff --git a/tool/main.go b/tool/main.go index 4232806..9ea3ba0 100644 --- a/tool/main.go +++ b/tool/main.go @@ -1,35 +1,17 @@ package main import ( - "context" - "fmt" - "github.com/muxi-Infra/muxi-micro/tool/curd/template" - "time" + curd "github.com/muxi-Infra/muxi-micro/tool/curd/cobra" + "github.com/spf13/cobra" ) func main() { - ttl := 10 * time.Second - instance, err := template.NewUserModels( - "root:2388287244@tcp(112.126.68.22:3306)/library?parseTime=true&charset=utf8mb4&loc=Local", - "112.126.68.22:6379", - "lhx2388287244", - 0, - -1, - ttl, - ) - if err != nil { - fmt.Println(err) + var Mu_xiCmd = &cobra.Command{ + Use: "Mu_xi", + Short: "Mu_xi-micro 总命令", } - user := template.User{ - Password: "666", - Username: "test777", - Mobile: "1145141919810", - } - err = instance.Create(context.Background(), &user) - if err != nil { - fmt.Println(err) - } - fmt.Println(user) - select {} + curd.InitCurdCobra(Mu_xiCmd) + + _ = Mu_xiCmd.Execute() } From 4f8530f8f409a1c957cfc5bbd2fb8b1aa679171f Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Mon, 25 Aug 2025 15:51:17 +0800 Subject: [PATCH 09/19] =?UTF-8?q?:=20=E6=96=B0=E5=A2=9E=E6=97=A0?= =?UTF-8?q?=E7=BC=93=E5=86=B2=E6=A8=A1=E6=9D=BF=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E4=B8=8D=E5=8F=AF=E8=A6=86=E7=9B=96=E9=80=89=E9=A1=B9;=20?= =?UTF-8?q?:=20=5Fgen.go=E5=A2=9E=E5=8A=A0=E4=BA=86=E4=B8=8D=E6=8E=A8?= =?UTF-8?q?=E8=8D=90=E4=BF=AE=E6=94=B9=E7=9A=84=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tool/curd/cobra/cobra.go | 18 ++++- tool/curd/create/create.go | 76 +++++++++++++------ tool/curd/example/UserModel.go | 2 +- tool/curd/example/UserModel_gen.go | 10 ++- tool/curd/example/model.go | 2 +- tool/curd/example/var.go | 2 +- tool/curd/template/no_cache/db.tpl | 74 ++++++++++++++++++ tool/curd/template/no_cache/example.tpl | 34 +++++++++ tool/curd/template/no_cache/header.tpl | 39 ++++++++++ tool/curd/template/no_cache/var.tpl | 9 +++ tool/curd/template/{ => with_cache}/cache.tpl | 0 tool/curd/template/{ => with_cache}/db.tpl | 6 +- .../template/{ => with_cache}/example.tpl | 0 .../curd/template/{ => with_cache}/header.tpl | 2 + tool/curd/template/{ => with_cache}/var.tpl | 0 tool/main.go | 4 +- 16 files changed, 238 insertions(+), 40 deletions(-) create mode 100644 tool/curd/template/no_cache/db.tpl create mode 100644 tool/curd/template/no_cache/example.tpl create mode 100644 tool/curd/template/no_cache/header.tpl create mode 100644 tool/curd/template/no_cache/var.tpl rename tool/curd/template/{ => with_cache}/cache.tpl (100%) rename tool/curd/template/{ => with_cache}/db.tpl (93%) rename tool/curd/template/{ => with_cache}/example.tpl (100%) rename tool/curd/template/{ => with_cache}/header.tpl (97%) rename tool/curd/template/{ => with_cache}/var.tpl (100%) diff --git a/tool/curd/cobra/cobra.go b/tool/curd/cobra/cobra.go index f44894b..333784c 100644 --- a/tool/curd/cobra/cobra.go +++ b/tool/curd/cobra/cobra.go @@ -25,6 +25,14 @@ func InitCurdCobra(parentCobra *cobra.Command) { if err != nil { return err } + cache, err := cmd.Flags().GetBool("cache") + if err != nil { + return err + } + cover, err := cmd.Flags().GetBool("cover") + if err != nil { + return err + } modelPath := filepath.Join(dir, "model.go") if _, err := os.Stat(modelPath); err != nil { @@ -35,15 +43,15 @@ func InitCurdCobra(parentCobra *cobra.Command) { return err } - err = create.CreateExample_gen(pkg, dir, table, index) + err = create.CreateExample_gen(pkg, dir, table, index, cache) if err != nil { return err } - err = create.CreateExample(pkg, dir, table) + err = create.CreateExample(pkg, dir, table, cache, cover) if err != nil { return err } - err = create.CreateVar(pkg, dir) + err = create.CreateVar(pkg, dir, cache, cover) if err != nil { fmt.Println(err) } @@ -51,8 +59,10 @@ func InitCurdCobra(parentCobra *cobra.Command) { }, } - curdCmd.Flags().String("package", "template", "生成文件的包名") + curdCmd.Flags().String("package", "model", "生成文件的包名") curdCmd.Flags().String("dir", ".", "model文件以及文件生成目录") + curdCmd.Flags().Bool("cache", false, "是否开启缓存") + curdCmd.Flags().Bool("cover", false, "是否覆盖除 _gen.go 外的另外两个文件") parentCobra.AddCommand(curdCmd) } diff --git a/tool/curd/create/create.go b/tool/curd/create/create.go index 7583677..ed20542 100644 --- a/tool/curd/create/create.go +++ b/tool/curd/create/create.go @@ -8,17 +8,16 @@ import ( "unicode" ) -func safeFilename(tableName string) string { - return strings.Map(func(r rune) rune { - if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' || r == '-' { - return r - } - return '_' - }, tableName) -} - -func CreateVar(pkg, dir string) error { - tmplPath := filepath.Join("curd", "template", "var.tpl") +func CreateVar(pkg, dir string, open, cover bool) error { + if cover == false && !CheckExist(dir, "var.go") { + return nil + } + var tmplPath string + if open { + tmplPath = filepath.Join("curd", "template", "with_cache", "var.tpl") + } else { + tmplPath = filepath.Join("curd", "template", "no_cache", "var.tpl") + } t, err := template.New("var").ParseFiles(tmplPath) if err != nil { @@ -46,15 +45,23 @@ func CreateVar(pkg, dir string) error { return nil } -func CreateExample(pkg, dir, table string) error { - tmplPath := filepath.Join("curd", "template", "example.tpl") +func CreateExample(pkg, dir, table string, open, cover bool) error { + if cover == false && !CheckExist(dir, safeFilename(table)+"model.go") { + return nil + } + var tmplPath string + if open { + tmplPath = filepath.Join("curd", "template", "with_cache", "example.tpl") + } else { + tmplPath = filepath.Join("curd", "template", "no_cache", "example.tpl") + } t, err := template.New("example").ParseFiles(tmplPath) if err != nil { return err } - outputPath := filepath.Join(dir, safeFilename(table)+"Model.go") + outputPath := filepath.Join(dir, safeFilename(table)+"model.go") file, err := os.Create(outputPath) if err != nil { return err @@ -77,11 +84,19 @@ func CreateExample(pkg, dir, table string) error { return nil } -func CreateExample_gen(pkg, dir, table string, fields []string) error { - tmplPath := []string{ - filepath.Join("curd", "template", "header.tpl"), - filepath.Join("curd", "template", "cache.tpl"), - filepath.Join("curd", "template", "db.tpl"), +func CreateExample_gen(pkg, dir, table string, fields []string, open bool) error { + var tmplPath []string + if open { + tmplPath = []string{ + filepath.Join("curd", "template", "with_cache", "header.tpl"), + filepath.Join("curd", "template", "with_cache", "cache.tpl"), + filepath.Join("curd", "template", "with_cache", "db.tpl"), + } + } else { + tmplPath = []string{ + filepath.Join("curd", "template", "no_cache", "header.tpl"), + filepath.Join("curd", "template", "no_cache", "db.tpl"), + } } t, err := template.New("header").ParseFiles(tmplPath...) @@ -89,7 +104,7 @@ func CreateExample_gen(pkg, dir, table string, fields []string) error { return err } - outputPath := filepath.Join(dir, safeFilename(table)+"Model_gen.go") + outputPath := filepath.Join(dir, safeFilename(table)+"model_gen.go") file, err := os.Create(outputPath) if err != nil { return err @@ -115,9 +130,22 @@ func CreateExample_gen(pkg, dir, table string, fields []string) error { return err } - // 设置为只读权限 - if err := file.Chmod(0444); err != nil { - return err - } return nil } + +func safeFilename(tableName string) string { + return strings.Map(func(r rune) rune { + if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' || r == '-' { + return r + } + return '_' + }, tableName) +} + +func CheckExist(dir, filename string) bool { + path := filepath.Join(dir, filename) + if _, err := os.Stat(path); err != nil { + return true + } + return false +} diff --git a/tool/curd/example/UserModel.go b/tool/curd/example/UserModel.go index 7d6952c..ab4e1ab 100644 --- a/tool/curd/example/UserModel.go +++ b/tool/curd/example/UserModel.go @@ -1,4 +1,4 @@ -package example +package model import ( "github.com/muxi-Infra/muxi-micro/pkg/logger" diff --git a/tool/curd/example/UserModel_gen.go b/tool/curd/example/UserModel_gen.go index eed8a49..6e6c3e5 100644 --- a/tool/curd/example/UserModel_gen.go +++ b/tool/curd/example/UserModel_gen.go @@ -1,4 +1,6 @@ -package example +// Code generated by muxi curd. DO NOT EDIT. + +package model import ( "context" @@ -61,15 +63,15 @@ func (u *UserExec) Create(ctx context.Context, data *User) error { return nil } -func (u *UserExec) FindOne(ctx context.Context, id int64) (*User, error) { - cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, id) +func (u *UserExec) FindOne(ctx context.Context, Id int64) (*User, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, Id) result, err, _ := group.Do(cachestr, func() (interface{}, error) { datacache := u.Get(ctx, cachestr) if datacache != nil { return datacache, nil } var data User - u.exec.AddWhere("id = ?", id) + u.exec.AddWhere("Id = ?", Id) err := u.exec.Find(ctx, &data) if err != nil { return nil, err diff --git a/tool/curd/example/model.go b/tool/curd/example/model.go index 9ba7034..c899f8e 100644 --- a/tool/curd/example/model.go +++ b/tool/curd/example/model.go @@ -1,4 +1,4 @@ -package example +package model type User struct { Id int64 `gorm:"primaryKey;autoIncrement"` diff --git a/tool/curd/example/var.go b/tool/curd/example/var.go index 3412d7f..ed4bc1f 100644 --- a/tool/curd/example/var.go +++ b/tool/curd/example/var.go @@ -1,4 +1,4 @@ -package example +package model import ( "github.com/muxi-Infra/muxi-micro/pkg/sql" diff --git a/tool/curd/template/no_cache/db.tpl b/tool/curd/template/no_cache/db.tpl new file mode 100644 index 0000000..bb88884 --- /dev/null +++ b/tool/curd/template/no_cache/db.tpl @@ -0,0 +1,74 @@ +{{- define "db2" -}} +func (u *{{.ModelName}}Exec) Create(ctx context.Context, data *{{.ModelName}}) error { + err := u.exec.Create(ctx, data) + if err != nil { + return err + } + return nil +} + +func (u *{{.ModelName}}Exec) FindOne(ctx context.Context, {{.Pr}} int64) (*{{.ModelName}}, error) { + result, err, _ := group.Do(fmt.Sprintf("%s%v", "{{.Pr}}", {{.Pr}}), func() (interface{}, error) { + var data {{.ModelName}} + u.exec.AddWhere("{{.Pr}} = ?", {{.Pr}}) + err := u.exec.Find(ctx, &data) + if err != nil { + return nil, err + } + if data.{{.Pr}} == 0 { + return nil, DBNotFound + } + return &data, nil + }) + if result == nil { + return nil, err + } + return result.(*{{.ModelName}}), err +} + +{{- $outer := . -}} +{{- range $notpr := .NotPrs}} + +func (u *{{$outer.ModelName}}Exec) FindBy{{$notpr}}(ctx context.Context, {{$notpr}} string) (*[]{{$outer.ModelName}}, error) { + result, err, _ := group.Do(fmt.Sprintf("%s%v", "{{$notpr}}", {{$notpr}}), func() (interface{}, error) { + var datas []{{$outer.ModelName}} + u.exec.AddWhere("{{$notpr}} = ?", {{$notpr}}) + err := u.exec.Find(ctx, &datas) + if err != nil { + return nil, err + } + if len(datas) == 0 { + return nil, DBNotFound + } + return &datas, nil + }) + if result == nil { + return nil, err + } + return result.(*[]{{$outer.ModelName}}), err +} +{{- end}} + +func (u *{{.ModelName}}Exec) Update(ctx context.Context, data *{{.ModelName}}) error { + u.exec.AddWhere("id = ?", data.{{.Pr}}) + err := u.exec.Update(ctx, data) + if err != nil { + return err + } + return nil +} + +func (u *{{.ModelName}}Exec) Delete(ctx context.Context, id int64) error { + var data {{.ModelName}} + d, err := u.FindOne(ctx, id) + if err != nil { + return err + } + data = *d + err = u.exec.Delete(ctx, &data) + if err != nil { + return err + } + return nil +} +{{- end -}} \ No newline at end of file diff --git a/tool/curd/template/no_cache/example.tpl b/tool/curd/template/no_cache/example.tpl new file mode 100644 index 0000000..0ebf500 --- /dev/null +++ b/tool/curd/template/no_cache/example.tpl @@ -0,0 +1,34 @@ +{{- define "example" -}} +package {{.PackageName}} + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/sql" + "time" +) + +var _ {{.ModelName}}Models = (*Extra{{.ModelName}}Exec)(nil) + +type {{.ModelName}}Models interface { + {{.ModelName}}Model + // 可以在这里添加额外的方法接口 +} + +type Extra{{.ModelName}}Exec struct { + *{{.ModelName}}Exec +} + +func New{{.ModelName}}Models(DBdsn string) ({{.ModelName}}Models, error) { + db, err := sql.ConnectDB(DBdsn, {{.ModelName}}{}) + if err != nil { + return nil, err + } + instance := New{{.ModelName}}Model(db) + + return &Extra{{.ModelName}}Exec{ + instance, + }, nil +} + +// 可以在这里添加额外的方法实现 +// func (e *Extra{{.ModelName}}Exec) ... +{{- end -}} \ No newline at end of file diff --git a/tool/curd/template/no_cache/header.tpl b/tool/curd/template/no_cache/header.tpl new file mode 100644 index 0000000..a24ad26 --- /dev/null +++ b/tool/curd/template/no_cache/header.tpl @@ -0,0 +1,39 @@ +{{- define "header" -}} +// Code generated by muxi curd. DO NOT EDIT. + +package {{.PackageName}} + +import ( + "context" + "fmt" + "github.com/muxi-Infra/muxi-micro/pkg/sql" + "golang.org/x/sync/singleflight" + "gorm.io/gorm" +) + +var group singleflight.Group + +type {{.ModelName}}Model interface { + Create(ctx context.Context, data *{{.ModelName}}) error + FindOne(ctx context.Context, id int64) (*{{.ModelName}}, error) + {{- range $notPr := .NotPrs}} + FindBy{{$notPr}}(ctx context.Context, {{$notPr}} string) (*[]{{$.ModelName}}, error) + {{- end}} + Update(ctx context.Context, data *{{.ModelName}}) error + Delete(ctx context.Context, id int64) error +} + +type {{.ModelName}}Exec struct { + exec *sql.Execute +} + +func New{{.ModelName}}Model(db *gorm.DB) *{{.ModelName}}Exec { + exec := sql.NewExecute({{.ModelName}}{}, db) + return &{{.ModelName}}Exec{ + exec: exec, + } +} + +{{template "db2" $}} + +{{- end -}} \ No newline at end of file diff --git a/tool/curd/template/no_cache/var.tpl b/tool/curd/template/no_cache/var.tpl new file mode 100644 index 0000000..267f325 --- /dev/null +++ b/tool/curd/template/no_cache/var.tpl @@ -0,0 +1,9 @@ +{{- define "var" -}} +package {{.PackageName}} + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/sql" +) + +var DBNotFound = sql.DBNotFound +{{- end -}} \ No newline at end of file diff --git a/tool/curd/template/cache.tpl b/tool/curd/template/with_cache/cache.tpl similarity index 100% rename from tool/curd/template/cache.tpl rename to tool/curd/template/with_cache/cache.tpl diff --git a/tool/curd/template/db.tpl b/tool/curd/template/with_cache/db.tpl similarity index 93% rename from tool/curd/template/db.tpl rename to tool/curd/template/with_cache/db.tpl index 1881c2d..4d5568d 100644 --- a/tool/curd/template/db.tpl +++ b/tool/curd/template/with_cache/db.tpl @@ -8,15 +8,15 @@ func (u *{{.ModelName}}Exec) Create(ctx context.Context, data *{{.ModelName}}) e return nil } -func (u *{{.ModelName}}Exec) FindOne(ctx context.Context, id int64) (*{{.ModelName}}, error) { - cachestr := fmt.Sprintf("%s%v", cache{{.ModelName}}{{.Pr}}Prefix, id) +func (u *{{.ModelName}}Exec) FindOne(ctx context.Context, {{.Pr}} int64) (*{{.ModelName}}, error) { + cachestr := fmt.Sprintf("%s%v", cache{{.ModelName}}{{.Pr}}Prefix, {{.Pr}}) result, err, _ := group.Do(cachestr, func() (interface{}, error) { datacache := u.Get(ctx, cachestr) if datacache != nil { return datacache, nil } var data {{.ModelName}} - u.exec.AddWhere("id = ?", id) + u.exec.AddWhere("{{.Pr}} = ?", {{.Pr}}) err := u.exec.Find(ctx, &data) if err != nil { return nil, err diff --git a/tool/curd/template/example.tpl b/tool/curd/template/with_cache/example.tpl similarity index 100% rename from tool/curd/template/example.tpl rename to tool/curd/template/with_cache/example.tpl diff --git a/tool/curd/template/header.tpl b/tool/curd/template/with_cache/header.tpl similarity index 97% rename from tool/curd/template/header.tpl rename to tool/curd/template/with_cache/header.tpl index c4c42e7..507fa75 100644 --- a/tool/curd/template/header.tpl +++ b/tool/curd/template/with_cache/header.tpl @@ -1,4 +1,6 @@ {{- define "header" -}} +// Code generated by muxi curd. DO NOT EDIT. + package {{.PackageName}} import ( diff --git a/tool/curd/template/var.tpl b/tool/curd/template/with_cache/var.tpl similarity index 100% rename from tool/curd/template/var.tpl rename to tool/curd/template/with_cache/var.tpl diff --git a/tool/main.go b/tool/main.go index 9ea3ba0..6a71349 100644 --- a/tool/main.go +++ b/tool/main.go @@ -7,8 +7,8 @@ import ( func main() { var Mu_xiCmd = &cobra.Command{ - Use: "Mu_xi", - Short: "Mu_xi-micro 总命令", + Use: "muxi", + Short: "muxi-micro 总命令", } curd.InitCurdCobra(Mu_xiCmd) From 011844a84abf248c1947987e064cb255093c2749 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Wed, 27 Aug 2025 16:58:28 +0800 Subject: [PATCH 10/19] =?UTF-8?q?:=20=E6=96=B0=E5=A2=9Ecurd=E7=9A=84?= =?UTF-8?q?test=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tool/cobra.go | 18 +++ tool/curd/{cobra/cobra.go => curd.go} | 26 ++--- tool/curd/curd_test.go | 98 ++++++++++++++++ tool/curd/example/UserModel.go | 8 +- tool/curd/example/UserModel_gen.go | 141 +----------------------- tool/curd/example/var.go | 2 - tool/curd/template/no_cache/example.tpl | 1 - tool/main.go | 17 --- 8 files changed, 131 insertions(+), 180 deletions(-) create mode 100644 tool/cobra.go rename tool/curd/{cobra/cobra.go => curd.go} (76%) create mode 100644 tool/curd/curd_test.go delete mode 100644 tool/main.go diff --git a/tool/cobra.go b/tool/cobra.go new file mode 100644 index 0000000..7f701b6 --- /dev/null +++ b/tool/cobra.go @@ -0,0 +1,18 @@ +package main + +import ( + "github.com/muxi-Infra/muxi-micro/tool/curd" + "github.com/spf13/cobra" +) + +func main() { + var muxiCmd = &cobra.Command{ + Use: "muxi", + Short: "muxi-micro 总命令", + } + + curdCmd := curd.InitCurdCobra() + muxiCmd.AddCommand(curdCmd) + + _ = muxiCmd.Execute() +} diff --git a/tool/curd/cobra/cobra.go b/tool/curd/curd.go similarity index 76% rename from tool/curd/cobra/cobra.go rename to tool/curd/curd.go index 333784c..8d161e6 100644 --- a/tool/curd/cobra/cobra.go +++ b/tool/curd/curd.go @@ -1,4 +1,4 @@ -package cobra +package curd import ( "fmt" @@ -9,7 +9,7 @@ import ( "path/filepath" ) -func InitCurdCobra(parentCobra *cobra.Command) { +func InitCurdCobra() *cobra.Command { // curd 子命令 var curdCmd = &cobra.Command{ Use: "curd", @@ -17,22 +17,10 @@ func InitCurdCobra(parentCobra *cobra.Command) { Long: "在你想要生成 curd 文件的地方创建 model.go,内含可通过 gorm 自动迁移的结构体," + "gorm 标签中 'primaryKey' 将被视为主键,主键和gorm标签中带有 'unique' 'index' 会自动生成查询", RunE: func(cmd *cobra.Command, args []string) error { - pkg, err := cmd.Flags().GetString("package") - if err != nil { - return err - } - dir, err := cmd.Flags().GetString("dir") - if err != nil { - return err - } - cache, err := cmd.Flags().GetBool("cache") - if err != nil { - return err - } - cover, err := cmd.Flags().GetBool("cover") - if err != nil { - return err - } + pkg, _ := cmd.Flags().GetString("package") + dir, _ := cmd.Flags().GetString("dir") + cache, _ := cmd.Flags().GetBool("cache") + cover, _ := cmd.Flags().GetBool("cover") modelPath := filepath.Join(dir, "model.go") if _, err := os.Stat(modelPath); err != nil { @@ -64,5 +52,5 @@ func InitCurdCobra(parentCobra *cobra.Command) { curdCmd.Flags().Bool("cache", false, "是否开启缓存") curdCmd.Flags().Bool("cover", false, "是否覆盖除 _gen.go 外的另外两个文件") - parentCobra.AddCommand(curdCmd) + return curdCmd } diff --git a/tool/curd/curd_test.go b/tool/curd/curd_test.go new file mode 100644 index 0000000..5d7cba7 --- /dev/null +++ b/tool/curd/curd_test.go @@ -0,0 +1,98 @@ +package curd + +import ( + "github.com/stretchr/testify/assert" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" +) + +func TestCurdError(t *testing.T) { + t.Run("can not find model.go", func(t *testing.T) { + tempDir, _ := ioutil.TempDir("", "curd_no_model_test") + defer os.RemoveAll(tempDir) + + curdCmd := InitCurdCobra() + + var output strings.Builder + curdCmd.SetOutput(&output) + curdCmd.SetArgs([]string{ + "--dir", tempDir, + }) + + err := curdCmd.Execute() + assert.ErrorContains(t, err, "The system cannot find the file specified.") + + }) + + t.Run("no primary key in model.go", func(t *testing.T) { + tempDir, _ := ioutil.TempDir("", "curd_error_model_test") + defer os.RemoveAll(tempDir) + modelPath := filepath.Join(tempDir, "model.go") + modelContent := `package model + +type User struct { + ID int64 + Name string ` + "`gorm:\"index\"`" + ` +} +` + _ = ioutil.WriteFile(modelPath, []byte(modelContent), 0644) + var output strings.Builder + curdCmd := InitCurdCobra() + curdCmd.SetOutput(&output) + curdCmd.SetArgs([]string{ + "--dir", tempDir, + }) + + err := curdCmd.Execute() + assert.ErrorContains(t, err, "you should create a primary key") + }) + + t.Run("too many primary key in model.go", func(t *testing.T) { + tempDir, _ := ioutil.TempDir("", "curd_error_model_test") + defer os.RemoveAll(tempDir) + modelPath := filepath.Join(tempDir, "model.go") + modelContent := `package model + +type User struct { + ID int64 ` + "`gorm:\"primaryKey;autoIncrement\"`" + ` + Name string ` + "`gorm:\"primaryKey;autoIncrement\"`" + ` +} +` + _ = ioutil.WriteFile(modelPath, []byte(modelContent), 0644) + var output strings.Builder + curdCmd := InitCurdCobra() + curdCmd.SetOutput(&output) + curdCmd.SetArgs([]string{ + "--dir", tempDir, + }) + + err := curdCmd.Execute() + assert.ErrorContains(t, err, "only one primary key need to be created") + }) + + t.Run("not correct type primary key in model.go", func(t *testing.T) { + tempDir, _ := ioutil.TempDir("", "curd_error_model_test") + defer os.RemoveAll(tempDir) + modelPath := filepath.Join(tempDir, "model.go") + modelContent := `package model + +type User struct { + ID int ` + "`gorm:\"primaryKey;autoIncrement\"`" + ` + Name string +} +` + _ = ioutil.WriteFile(modelPath, []byte(modelContent), 0644) + var output strings.Builder + curdCmd := InitCurdCobra() + curdCmd.SetOutput(&output) + curdCmd.SetArgs([]string{ + "--dir", tempDir, + }) + + err := curdCmd.Execute() + assert.ErrorContains(t, err, "primary key type should be int64") + }) +} diff --git a/tool/curd/example/UserModel.go b/tool/curd/example/UserModel.go index ab4e1ab..352cdcf 100644 --- a/tool/curd/example/UserModel.go +++ b/tool/curd/example/UserModel.go @@ -1,9 +1,7 @@ package model import ( - "github.com/muxi-Infra/muxi-micro/pkg/logger" "github.com/muxi-Infra/muxi-micro/pkg/sql" - "time" ) var _ UserModels = (*ExtraUserExec)(nil) @@ -17,14 +15,12 @@ type ExtraUserExec struct { *UserExec } -func NewUserModels(DBdsn, redisAddr, redisPassword string, number int, ttlForCache, ttlForSet time.Duration, l logger.Logger) (UserModels, error) { +func NewUserModels(DBdsn string) (UserModels, error) { db, err := sql.ConnectDB(DBdsn, User{}) if err != nil { return nil, err } - cache := sql.ConnectCache(redisAddr, redisPassword, number, ttlForCache, ttlForSet) - - instance := NewUserModel(db, cache, l) + instance := NewUserModel(db) return &ExtraUserExec{ instance, diff --git a/tool/curd/example/UserModel_gen.go b/tool/curd/example/UserModel_gen.go index 6e6c3e5..e3a837e 100644 --- a/tool/curd/example/UserModel_gen.go +++ b/tool/curd/example/UserModel_gen.go @@ -4,21 +4,12 @@ package model import ( "context" - "encoding/json" - "errors" "fmt" - "github.com/muxi-Infra/muxi-micro/pkg/logger" "github.com/muxi-Infra/muxi-micro/pkg/sql" "golang.org/x/sync/singleflight" "gorm.io/gorm" ) -const ( - cacheUserUsernamePrefix = "cache:User:Username:" - cacheUserMobilePrefix = "cache:User:Mobile:" - cacheUserIdPrefix = "cache:User:Id:" -) - var group singleflight.Group type UserModel interface { @@ -32,44 +23,25 @@ type UserModel interface { type UserExec struct { exec *sql.Execute - cacheExec *sql.CacheExecute - logger logger.Logger } -func NewUserModel(db *gorm.DB, cache *sql.CacheExecute, logger logger.Logger) *UserExec { +func NewUserModel(db *gorm.DB) *UserExec { exec := sql.NewExecute(User{}, db) return &UserExec{ exec: exec, - cacheExec: cache, - logger: logger, } } -// 序列化 -func UnMarshalJSON(s string, model *User) error { - return json.Unmarshal([]byte(s), model) -} - -func UnMarshalString(s string, model *[]int64) error { - return json.Unmarshal([]byte(s), model) -} - func (u *UserExec) Create(ctx context.Context, data *User) error { err := u.exec.Create(ctx, data) if err != nil { return err } - go u.DelCache(ctx, data) return nil } func (u *UserExec) FindOne(ctx context.Context, Id int64) (*User, error) { - cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, Id) - result, err, _ := group.Do(cachestr, func() (interface{}, error) { - datacache := u.Get(ctx, cachestr) - if datacache != nil { - return datacache, nil - } + result, err, _ := group.Do(fmt.Sprintf("%s%v", "Id", Id), func() (interface{}, error) { var data User u.exec.AddWhere("Id = ?", Id) err := u.exec.Find(ctx, &data) @@ -79,7 +51,6 @@ func (u *UserExec) FindOne(ctx context.Context, Id int64) (*User, error) { if data.Id == 0 { return nil, DBNotFound } - go u.Set(cachestr, &data) return &data, nil }) if result == nil { @@ -89,23 +60,16 @@ func (u *UserExec) FindOne(ctx context.Context, Id int64) (*User, error) { } func (u *UserExec) FindByUsername(ctx context.Context, Username string) (*[]User, error) { - cachestr := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, Username) - result, err, _ := group.Do(cachestr, func() (interface{}, error) { - cacheval, err := u.cacheExec.GetCache(cachestr, ctx) - datascache := u.GetMany(ctx, cacheval) - if datascache != nil { - return datascache, nil - } + result, err, _ := group.Do(fmt.Sprintf("%s%v", "Username", Username), func() (interface{}, error) { var datas []User u.exec.AddWhere("Username = ?", Username) - err = u.exec.Find(ctx, &datas) + err := u.exec.Find(ctx, &datas) if err != nil { return nil, err } if len(datas) == 0 { return nil, DBNotFound } - go u.SetMany(cachestr, &datas) return &datas, nil }) if result == nil { @@ -115,23 +79,16 @@ func (u *UserExec) FindByUsername(ctx context.Context, Username string) (*[]User } func (u *UserExec) FindByMobile(ctx context.Context, Mobile string) (*[]User, error) { - cachestr := fmt.Sprintf("%s%v", cacheUserMobilePrefix, Mobile) - result, err, _ := group.Do(cachestr, func() (interface{}, error) { - cacheval, err := u.cacheExec.GetCache(cachestr, ctx) - datascache := u.GetMany(ctx, cacheval) - if datascache != nil { - return datascache, nil - } + result, err, _ := group.Do(fmt.Sprintf("%s%v", "Mobile", Mobile), func() (interface{}, error) { var datas []User u.exec.AddWhere("Mobile = ?", Mobile) - err = u.exec.Find(ctx, &datas) + err := u.exec.Find(ctx, &datas) if err != nil { return nil, err } if len(datas) == 0 { return nil, DBNotFound } - go u.SetMany(cachestr, &datas) return &datas, nil }) if result == nil { @@ -146,7 +103,6 @@ func (u *UserExec) Update(ctx context.Context, data *User) error { if err != nil { return err } - go u.DelCache(ctx, data) return nil } @@ -161,90 +117,5 @@ func (u *UserExec) Delete(ctx context.Context, id int64) error { if err != nil { return err } - go u.DelCache(ctx, &data) - return nil -} - -// cache -func (u *UserExec) DelCache(ctx context.Context, model *User) { - err := u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserIdPrefix, model.Id), ctx) - if err != nil { - u.logger.Error("Primary key cache delete failure", err) - } - err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserUsernamePrefix, model.Username), ctx) - if err != nil { - u.logger.Warn("Not-primary key cache delete failure", err) - } - err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserMobilePrefix, model.Mobile), ctx) - if err != nil { - u.logger.Warn("Not-primary key cache delete failure", err) - } -} - -func (u *UserExec) Get(ctx context.Context, cachestr string) *User { - var data User - cacheval, err := u.cacheExec.GetCache(cachestr, ctx) - if err == nil { - err := UnMarshalJSON(cacheval, &data) - if err != nil { - u.logger.Warn("UnMarshal failure: ", err) - return nil - } - return &data - } - if !errors.Is(err, CacheNotFound) { - u.logger.Warn("Primary key cache get failure: ", err) - return nil - } - return nil -} - -func (u *UserExec) GetMany(ctx context.Context, cachestr string) *[]User { - var datas []User - cacheval, err := u.cacheExec.GetCache(cachestr, ctx) - if err == nil { - var key []int64 - err := UnMarshalString(cacheval, &key) - if err != nil { - u.logger.Warn("UnMarshal failure: ", err) - return nil - } - for _, c := range key { - data, err := u.FindOne(ctx, c) - if err != nil { - return nil - } - datas = append(datas, *data) - } - return &datas - } - if !errors.Is(err, CacheNotFound) { - u.logger.Warn("Not-primary key cache get failure: ", err) - return nil - } return nil -} - -func (u *UserExec) Set(cachestr string, data *User) { - ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) - err := u.cacheExec.SetCache(cachestr, ctx, data) - if err != nil { - u.logger.Warn("Primary key cache set failure: ", err) - } - cancel() -} - -func (u *UserExec) SetMany(cachestr string, data *[]User) { - ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) - var key []int64 - for _, v := range *data { - key = append(key, v.Id) - cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, v.Id) - u.Set(cachestr, &v) - } - err := u.cacheExec.SetCache(cachestr, ctx, &key) - if err != nil { - u.logger.Warn("Not-primary key cache set failure: ", err) - } - cancel() } \ No newline at end of file diff --git a/tool/curd/example/var.go b/tool/curd/example/var.go index ed4bc1f..0bde662 100644 --- a/tool/curd/example/var.go +++ b/tool/curd/example/var.go @@ -4,6 +4,4 @@ import ( "github.com/muxi-Infra/muxi-micro/pkg/sql" ) -const CacheNotFound = sql.CacheNotFound - var DBNotFound = sql.DBNotFound \ No newline at end of file diff --git a/tool/curd/template/no_cache/example.tpl b/tool/curd/template/no_cache/example.tpl index 0ebf500..7bdbd6e 100644 --- a/tool/curd/template/no_cache/example.tpl +++ b/tool/curd/template/no_cache/example.tpl @@ -3,7 +3,6 @@ package {{.PackageName}} import ( "github.com/muxi-Infra/muxi-micro/pkg/sql" - "time" ) var _ {{.ModelName}}Models = (*Extra{{.ModelName}}Exec)(nil) diff --git a/tool/main.go b/tool/main.go deleted file mode 100644 index 6a71349..0000000 --- a/tool/main.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - curd "github.com/muxi-Infra/muxi-micro/tool/curd/cobra" - "github.com/spf13/cobra" -) - -func main() { - var Mu_xiCmd = &cobra.Command{ - Use: "muxi", - Short: "muxi-micro 总命令", - } - - curd.InitCurdCobra(Mu_xiCmd) - - _ = Mu_xiCmd.Execute() -} From 8e28ee9fa1be2bbbd530c32ab32e49945cb168eb Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Wed, 27 Aug 2025 17:29:20 +0800 Subject: [PATCH 11/19] =?UTF-8?q?:=20=E6=96=B0=E5=A2=9Ecurd=E7=9A=84?= =?UTF-8?q?=E4=BD=BF=E7=94=A8example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/curd/curd.go | 51 ++++++++++ tool/curd/example/UserModel.go | 10 +- tool/curd/example/UserModel_gen.go | 143 +++++++++++++++++++++++++++-- tool/curd/example/model.go | 2 +- tool/curd/example/var.go | 4 +- 5 files changed, 198 insertions(+), 12 deletions(-) create mode 100644 example/curd/curd.go diff --git a/example/curd/curd.go b/example/curd/curd.go new file mode 100644 index 0000000..12010ba --- /dev/null +++ b/example/curd/curd.go @@ -0,0 +1,51 @@ +package main + +import ( + "context" + "fmt" + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/logger/zapx" + "github.com/muxi-Infra/muxi-micro/tool/curd/example" + "log" + "time" +) + +func main() { + DBdsn := "your db dsn" + redisAddr := "your redis addr" + redisPassword := "your redis password" + redisDB := 0 + // 缓存持续时间 + ttlForCache := 5 * time.Second + // 异步设置缓存时间 + ttlForSet := 5 * time.Second + // 日志记录 redis 错误 + l := zapx.NewDefaultZapLogger(logger.EnvTest, true, "./logs") + instance, err := example.NewUserModels( + DBdsn, + redisAddr, + redisPassword, + redisDB, + ttlForCache, + ttlForSet, + l, + ) + if err != nil { + log.Fatal(err) + } + //user := example.User{ + // Id: 7, + // Username: "example3", + // Password: "123456", + // Mobile: "example111", + //} + //_ = instance.Create(context.Background(), &user) + //_ = instance.Update(context.Background(), &user) + //_ = instance.Delete(context.Background(), 7) + //value, err := instance.FindOne(context.Background(), 3) + value, err := instance.FindByMobile(context.Background(), "123456") + if err != nil { + log.Fatal(err) + } + fmt.Println(value) +} diff --git a/tool/curd/example/UserModel.go b/tool/curd/example/UserModel.go index 352cdcf..7d6952c 100644 --- a/tool/curd/example/UserModel.go +++ b/tool/curd/example/UserModel.go @@ -1,7 +1,9 @@ -package model +package example import ( + "github.com/muxi-Infra/muxi-micro/pkg/logger" "github.com/muxi-Infra/muxi-micro/pkg/sql" + "time" ) var _ UserModels = (*ExtraUserExec)(nil) @@ -15,12 +17,14 @@ type ExtraUserExec struct { *UserExec } -func NewUserModels(DBdsn string) (UserModels, error) { +func NewUserModels(DBdsn, redisAddr, redisPassword string, number int, ttlForCache, ttlForSet time.Duration, l logger.Logger) (UserModels, error) { db, err := sql.ConnectDB(DBdsn, User{}) if err != nil { return nil, err } - instance := NewUserModel(db) + cache := sql.ConnectCache(redisAddr, redisPassword, number, ttlForCache, ttlForSet) + + instance := NewUserModel(db, cache, l) return &ExtraUserExec{ instance, diff --git a/tool/curd/example/UserModel_gen.go b/tool/curd/example/UserModel_gen.go index e3a837e..e12888e 100644 --- a/tool/curd/example/UserModel_gen.go +++ b/tool/curd/example/UserModel_gen.go @@ -1,15 +1,24 @@ // Code generated by muxi curd. DO NOT EDIT. -package model +package example import ( "context" + "encoding/json" + "errors" "fmt" + "github.com/muxi-Infra/muxi-micro/pkg/logger" "github.com/muxi-Infra/muxi-micro/pkg/sql" "golang.org/x/sync/singleflight" "gorm.io/gorm" ) +const ( + cacheUserUsernamePrefix = "cache:User:Username:" + cacheUserMobilePrefix = "cache:User:Mobile:" + cacheUserIdPrefix = "cache:User:Id:" +) + var group singleflight.Group type UserModel interface { @@ -23,25 +32,44 @@ type UserModel interface { type UserExec struct { exec *sql.Execute + cacheExec *sql.CacheExecute + logger logger.Logger } -func NewUserModel(db *gorm.DB) *UserExec { +func NewUserModel(db *gorm.DB, cache *sql.CacheExecute, logger logger.Logger) *UserExec { exec := sql.NewExecute(User{}, db) return &UserExec{ exec: exec, + cacheExec: cache, + logger: logger, } } +// 序列化 +func UnMarshalJSON(s string, model *User) error { + return json.Unmarshal([]byte(s), model) +} + +func UnMarshalString(s string, model *[]int64) error { + return json.Unmarshal([]byte(s), model) +} + func (u *UserExec) Create(ctx context.Context, data *User) error { err := u.exec.Create(ctx, data) if err != nil { return err } + go u.DelCache(ctx, data) return nil } func (u *UserExec) FindOne(ctx context.Context, Id int64) (*User, error) { - result, err, _ := group.Do(fmt.Sprintf("%s%v", "Id", Id), func() (interface{}, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, Id) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + datacache := u.Get(ctx, cachestr) + if datacache != nil { + return datacache, nil + } var data User u.exec.AddWhere("Id = ?", Id) err := u.exec.Find(ctx, &data) @@ -51,6 +79,7 @@ func (u *UserExec) FindOne(ctx context.Context, Id int64) (*User, error) { if data.Id == 0 { return nil, DBNotFound } + go u.Set(cachestr, &data) return &data, nil }) if result == nil { @@ -60,16 +89,23 @@ func (u *UserExec) FindOne(ctx context.Context, Id int64) (*User, error) { } func (u *UserExec) FindByUsername(ctx context.Context, Username string) (*[]User, error) { - result, err, _ := group.Do(fmt.Sprintf("%s%v", "Username", Username), func() (interface{}, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, Username) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + datascache := u.GetMany(ctx, cacheval) + if datascache != nil { + return datascache, nil + } var datas []User u.exec.AddWhere("Username = ?", Username) - err := u.exec.Find(ctx, &datas) + err = u.exec.Find(ctx, &datas) if err != nil { return nil, err } if len(datas) == 0 { return nil, DBNotFound } + go u.SetMany(cachestr, &datas) return &datas, nil }) if result == nil { @@ -79,16 +115,23 @@ func (u *UserExec) FindByUsername(ctx context.Context, Username string) (*[]User } func (u *UserExec) FindByMobile(ctx context.Context, Mobile string) (*[]User, error) { - result, err, _ := group.Do(fmt.Sprintf("%s%v", "Mobile", Mobile), func() (interface{}, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserMobilePrefix, Mobile) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + datascache := u.GetMany(ctx, cacheval) + if datascache != nil { + return datascache, nil + } var datas []User u.exec.AddWhere("Mobile = ?", Mobile) - err := u.exec.Find(ctx, &datas) + err = u.exec.Find(ctx, &datas) if err != nil { return nil, err } if len(datas) == 0 { return nil, DBNotFound } + go u.SetMany(cachestr, &datas) return &datas, nil }) if result == nil { @@ -103,6 +146,7 @@ func (u *UserExec) Update(ctx context.Context, data *User) error { if err != nil { return err } + go u.DelCache(ctx, data) return nil } @@ -117,5 +161,90 @@ func (u *UserExec) Delete(ctx context.Context, id int64) error { if err != nil { return err } + go u.DelCache(ctx, &data) + return nil +} + +// cache +func (u *UserExec) DelCache(ctx context.Context, model *User) { + err := u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserIdPrefix, model.Id), ctx) + if err != nil { + u.logger.Error("Primary key cache delete failure", err) + } + err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserUsernamePrefix, model.Username), ctx) + if err != nil { + u.logger.Warn("Not-primary key cache delete failure", err) + } + err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserMobilePrefix, model.Mobile), ctx) + if err != nil { + u.logger.Warn("Not-primary key cache delete failure", err) + } +} + +func (u *UserExec) Get(ctx context.Context, cachestr string) *User { + var data User + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + if err == nil { + err := UnMarshalJSON(cacheval, &data) + if err != nil { + u.logger.Warn("UnMarshal failure: ", err) + return nil + } + return &data + } + if !errors.Is(err, CacheNotFound) { + u.logger.Warn("Primary key cache get failure: ", err) + return nil + } + return nil +} + +func (u *UserExec) GetMany(ctx context.Context, cachestr string) *[]User { + var datas []User + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + if err == nil { + var key []int64 + err := UnMarshalString(cacheval, &key) + if err != nil { + u.logger.Warn("UnMarshal failure: ", err) + return nil + } + for _, c := range key { + data, err := u.FindOne(ctx, c) + if err != nil { + return nil + } + datas = append(datas, *data) + } + return &datas + } + if !errors.Is(err, CacheNotFound) { + u.logger.Warn("Not-primary key cache get failure: ", err) + return nil + } return nil +} + +func (u *UserExec) Set(cachestr string, data *User) { + ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) + err := u.cacheExec.SetCache(cachestr, ctx, data) + if err != nil { + u.logger.Warn("Primary key cache set failure: ", err) + } + cancel() +} + +func (u *UserExec) SetMany(cachestr string, data *[]User) { + ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) + var key []int64 + for _, v := range *data { + key = append(key, v.Id) + cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, v.Id) + u.Set(cachestr, &v) + } + err := u.cacheExec.SetCache(cachestr, ctx, &key) + if err != nil { + u.logger.Warn("Not-primary key cache set failure: ", err) + } + cancel() } \ No newline at end of file diff --git a/tool/curd/example/model.go b/tool/curd/example/model.go index c899f8e..9ba7034 100644 --- a/tool/curd/example/model.go +++ b/tool/curd/example/model.go @@ -1,4 +1,4 @@ -package model +package example type User struct { Id int64 `gorm:"primaryKey;autoIncrement"` diff --git a/tool/curd/example/var.go b/tool/curd/example/var.go index 0bde662..3412d7f 100644 --- a/tool/curd/example/var.go +++ b/tool/curd/example/var.go @@ -1,7 +1,9 @@ -package model +package example import ( "github.com/muxi-Infra/muxi-micro/pkg/sql" ) +const CacheNotFound = sql.CacheNotFound + var DBNotFound = sql.DBNotFound \ No newline at end of file From 1a9cde53c1151bf434f177174bd6df62fd7ba559 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Mon, 1 Sep 2025 18:35:32 +0800 Subject: [PATCH 12/19] =?UTF-8?q?:=20=E4=B8=80=E4=BA=9B=E5=B0=8F?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/kafka/producer.go | 2 +- pkg/sql/cache.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/kafka/producer.go b/pkg/kafka/producer.go index 73496e7..ba59da1 100644 --- a/pkg/kafka/producer.go +++ b/pkg/kafka/producer.go @@ -119,7 +119,7 @@ func (p *AsyncProducer) SendMessage(topic, key, value string) (int32, int64, err p.producer.Input() <- msg //异步不能在这里查错 - return -1, -1, nil + return 0, 0, nil } func (p *AsyncProducer) Close() error { diff --git a/pkg/sql/cache.go b/pkg/sql/cache.go index 8caaa32..4e51a06 100644 --- a/pkg/sql/cache.go +++ b/pkg/sql/cache.go @@ -16,7 +16,7 @@ type CacheExecute struct { SetTTl time.Duration //写入缓存的允许最大时长 } -func ConnectCache(addr, password string, number int, TTL, TTL2 time.Duration) *CacheExecute { +func ConnectCache(addr, password string, number int, CacheTTL, SetTTL time.Duration) *CacheExecute { rdb := redis.NewClient(&redis.Options{ Addr: addr, Password: password, @@ -25,8 +25,8 @@ func ConnectCache(addr, password string, number int, TTL, TTL2 time.Duration) *C return &CacheExecute{ rdb, - TTL, - TTL2, + CacheTTL, + SetTTL, } } From 3e6ab16f8bfbe9989b34ad360ab814117e2bda93 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Mon, 1 Sep 2025 19:03:32 +0800 Subject: [PATCH 13/19] =?UTF-8?q?:=20(template)=E7=94=B1=E4=BA=8Elogg?= =?UTF-8?q?er=E5=8C=85=E6=94=B9=E4=BA=86=EF=BC=8C=E6=95=85=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=BA=86=E6=A8=A1=E6=9D=BF=E4=B8=ADlogger=E5=8C=85?= =?UTF-8?q?=E7=9A=84=E4=BD=BF=E7=94=A8=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tool/curd/example/UserModel_gen.go | 18 +++++++++--------- tool/curd/template/with_cache/cache.tpl | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tool/curd/example/UserModel_gen.go b/tool/curd/example/UserModel_gen.go index e12888e..55117e8 100644 --- a/tool/curd/example/UserModel_gen.go +++ b/tool/curd/example/UserModel_gen.go @@ -169,15 +169,15 @@ func (u *UserExec) Delete(ctx context.Context, id int64) error { func (u *UserExec) DelCache(ctx context.Context, model *User) { err := u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserIdPrefix, model.Id), ctx) if err != nil { - u.logger.Error("Primary key cache delete failure", err) + u.logger.Error("主键缓存删除失败", logger.Int64("Id", model.Id),logger.Error(err)) } err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserUsernamePrefix, model.Username), ctx) if err != nil { - u.logger.Warn("Not-primary key cache delete failure", err) + u.logger.Warn("非主键缓存删除失败", logger.String("Username", model.Username),logger.Error(err)) } err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserMobilePrefix, model.Mobile), ctx) if err != nil { - u.logger.Warn("Not-primary key cache delete failure", err) + u.logger.Warn("非主键缓存删除失败", logger.String("Mobile", model.Mobile),logger.Error(err)) } } @@ -187,13 +187,13 @@ func (u *UserExec) Get(ctx context.Context, cachestr string) *User { if err == nil { err := UnMarshalJSON(cacheval, &data) if err != nil { - u.logger.Warn("UnMarshal failure: ", err) + u.logger.Warn("Json 序列化出错", logger.Error(err)) return nil } return &data } if !errors.Is(err, CacheNotFound) { - u.logger.Warn("Primary key cache get failure: ", err) + u.logger.Warn("主键缓存获取失败", logger.Error(err)) return nil } return nil @@ -206,7 +206,7 @@ func (u *UserExec) GetMany(ctx context.Context, cachestr string) *[]User { var key []int64 err := UnMarshalString(cacheval, &key) if err != nil { - u.logger.Warn("UnMarshal failure: ", err) + u.logger.Warn("Json 序列化出错", logger.Error(err)) return nil } for _, c := range key { @@ -219,7 +219,7 @@ func (u *UserExec) GetMany(ctx context.Context, cachestr string) *[]User { return &datas } if !errors.Is(err, CacheNotFound) { - u.logger.Warn("Not-primary key cache get failure: ", err) + u.logger.Warn("非主键缓存获取失败", logger.Error(err)) return nil } return nil @@ -229,7 +229,7 @@ func (u *UserExec) Set(cachestr string, data *User) { ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) err := u.cacheExec.SetCache(cachestr, ctx, data) if err != nil { - u.logger.Warn("Primary key cache set failure: ", err) + u.logger.Warn("主键缓存设置失败", logger.Error(err)) } cancel() } @@ -244,7 +244,7 @@ func (u *UserExec) SetMany(cachestr string, data *[]User) { } err := u.cacheExec.SetCache(cachestr, ctx, &key) if err != nil { - u.logger.Warn("Not-primary key cache set failure: ", err) + u.logger.Warn("非主键缓存设置失败", logger.Error(err)) } cancel() } \ No newline at end of file diff --git a/tool/curd/template/with_cache/cache.tpl b/tool/curd/template/with_cache/cache.tpl index f4db372..36eb7a1 100644 --- a/tool/curd/template/with_cache/cache.tpl +++ b/tool/curd/template/with_cache/cache.tpl @@ -3,13 +3,13 @@ func (u *{{.ModelName}}Exec) DelCache(ctx context.Context, model *{{.ModelName}}) { err := u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cache{{.ModelName}}{{.Pr}}Prefix, model.{{.Pr}}), ctx) if err != nil { - u.logger.Error("Primary key cache delete failure", err) + u.logger.Error("主键缓存删除失败", logger.Int64("{{.Pr}}", model.{{.Pr}}),logger.Error(err)) } {{- $outer := . -}} {{- range $notpr := .NotPrs}} err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cache{{$outer.ModelName}}{{$notpr}}Prefix, model.{{$notpr}}), ctx) if err != nil { - u.logger.Warn("Not-primary key cache delete failure", err) + u.logger.Warn("非主键缓存删除失败", logger.String("{{$notpr}}", model.{{$notpr}}),logger.Error(err)) } {{- end}} } @@ -20,13 +20,13 @@ func (u *{{.ModelName}}Exec) Get(ctx context.Context, cachestr string) *{{.Model if err == nil { err := UnMarshalJSON(cacheval, &data) if err != nil { - u.logger.Warn("UnMarshal failure: ", err) + u.logger.Warn("Json 序列化出错", logger.Error(err)) return nil } return &data } if !errors.Is(err, CacheNotFound) { - u.logger.Warn("Primary key cache get failure: ", err) + u.logger.Warn("主键缓存获取失败", logger.Error(err)) return nil } return nil @@ -39,7 +39,7 @@ func (u *{{.ModelName}}Exec) GetMany(ctx context.Context, cachestr string) *[]{{ var key []int64 err := UnMarshalString(cacheval, &key) if err != nil { - u.logger.Warn("UnMarshal failure: ", err) + u.logger.Warn("Json 序列化出错", logger.Error(err)) return nil } for _, c := range key { @@ -52,7 +52,7 @@ func (u *{{.ModelName}}Exec) GetMany(ctx context.Context, cachestr string) *[]{{ return &datas } if !errors.Is(err, CacheNotFound) { - u.logger.Warn("Not-primary key cache get failure: ", err) + u.logger.Warn("非主键缓存获取失败", logger.Error(err)) return nil } return nil @@ -62,7 +62,7 @@ func (u *{{.ModelName}}Exec) Set(cachestr string, data *{{.ModelName}}) { ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) err := u.cacheExec.SetCache(cachestr, ctx, data) if err != nil { - u.logger.Warn("Primary key cache set failure: ", err) + u.logger.Warn("主键缓存设置失败", logger.Error(err)) } cancel() } @@ -77,7 +77,7 @@ func (u *{{.ModelName}}Exec) SetMany(cachestr string, data *[]{{.ModelName}}) { } err := u.cacheExec.SetCache(cachestr, ctx, &key) if err != nil { - u.logger.Warn("Not-primary key cache set failure: ", err) + u.logger.Warn("非主键缓存设置失败", logger.Error(err)) } cancel() } From 472c067942bffe23c2070d1c6c1b0f4106c902f1 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Mon, 1 Sep 2025 19:11:53 +0800 Subject: [PATCH 14/19] =?UTF-8?q?:=20=E6=94=B9=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=B8=8Bcurd=5Ftest=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tool/curd/curd_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tool/curd/curd_test.go b/tool/curd/curd_test.go index 5d7cba7..8632587 100644 --- a/tool/curd/curd_test.go +++ b/tool/curd/curd_test.go @@ -23,8 +23,9 @@ func TestCurdError(t *testing.T) { }) err := curdCmd.Execute() - assert.ErrorContains(t, err, "The system cannot find the file specified.") - + if err == nil { + t.Fatal("Expected an error, got nil") + } }) t.Run("no primary key in model.go", func(t *testing.T) { From d6bf6e818a056fff95c221afd7e2c13912f3331a Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Mon, 1 Sep 2025 19:15:11 +0800 Subject: [PATCH 15/19] =?UTF-8?q?:=20=E4=BF=AE=E6=94=B9=E4=BA=86curd?= =?UTF-8?q?=E7=9A=84example=E9=80=82=E9=85=8D=E6=96=B0logger=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/curd/curd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/curd/curd.go b/example/curd/curd.go index 12010ba..b7802c0 100644 --- a/example/curd/curd.go +++ b/example/curd/curd.go @@ -20,7 +20,7 @@ func main() { // 异步设置缓存时间 ttlForSet := 5 * time.Second // 日志记录 redis 错误 - l := zapx.NewDefaultZapLogger(logger.EnvTest, true, "./logs") + l := zapx.NewDefaultZapLogger("./logs", logger.EnvTest) instance, err := example.NewUserModels( DBdsn, redisAddr, From 9566583dabea53036315b801f8798ae9ebf55ec5 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Mon, 1 Sep 2025 19:39:19 +0800 Subject: [PATCH 16/19] =?UTF-8?q?:=20(timeout.go)=20=E5=9B=9E?= =?UTF-8?q?=E9=80=80=E4=BA=86timeout=E5=8C=85=E7=9A=84=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 18 +++++++++--------- go.sum | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 37ed3e9..fd7883f 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( github.com/fsnotify/fsnotify v1.9.0 github.com/gin-contrib/cors v1.7.6 github.com/gin-contrib/pprof v1.5.3 - github.com/gin-contrib/timeout v1.1.0 github.com/gin-gonic/gin v1.10.1 github.com/go-redis/redis v6.15.9+incompatible github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 @@ -58,21 +57,22 @@ require ( github.com/aliyun/credentials-go v1.4.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/buger/jsonparser v1.1.1 // indirect - github.com/bytedance/sonic v1.13.3 // indirect - github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/bytedance/sonic v1.14.0 // indirect + github.com/bytedance/sonic/loader v0.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/clbanning/mxj/v2 v2.5.5 // indirect - github.com/cloudwego/base64x v0.1.5 // indirect + github.com/cloudwego/base64x v0.1.6 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set v1.7.1 // indirect github.com/eapache/go-resiliency v1.7.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.9 // indirect + github.com/gabriel-vasile/mimetype v1.4.10 // indirect github.com/gin-contrib/sse v1.1.0 // indirect + github.com/gin-contrib/timeout v1.0.2 // 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.26.0 // indirect + github.com/go-playground/validator/v10 v10.27.0 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/goccy/go-json v0.10.5 // indirect @@ -92,7 +92,7 @@ require ( github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.0 // indirect - github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // 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 @@ -122,14 +122,14 @@ require ( github.com/ugorji/go/codec v1.3.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/arch v0.18.0 // indirect + golang.org/x/arch v0.20.0 // indirect golang.org/x/crypto v0.41.0 // indirect golang.org/x/net v0.43.0 // indirect golang.org/x/sys v0.35.0 // indirect golang.org/x/text v0.28.0 // indirect golang.org/x/time v0.12.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/protobuf v1.36.6 // indirect + google.golang.org/protobuf v1.36.8 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect skywalking.apache.org/repo/goapi v0.0.0-20220401015832-2c9eee9481eb // indirect diff --git a/go.sum b/go.sum index 7858973..4cdceaf 100644 --- a/go.sum +++ b/go.sum @@ -86,9 +86,13 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bytedance/sonic v1.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF0= github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= +github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= +github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -98,6 +102,8 @@ github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= +github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -133,6 +139,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= +github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0= +github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/cors v1.7.6 h1:3gQ8GMzs1Ylpf70y8bMw4fVpycXIeX1ZemuSQIsnQQY= github.com/gin-contrib/cors v1.7.6/go.mod h1:Ulcl+xN4jel9t1Ry8vqph23a60FwH9xVLd+3ykmTjOk= @@ -141,6 +149,8 @@ github.com/gin-contrib/pprof v1.5.3/go.mod h1:0+LQSZ4SLO0B6+2n6JBzaEygpTBxe/nI+Y github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-contrib/timeout v1.0.2 h1:r4RoqvDHs0rCLUCK54VSORt5c2ICKWUHNa+MFrJ3jTY= +github.com/gin-contrib/timeout v1.0.2/go.mod h1:2nd5bn+1BdaPEKD6ksEkRJQhPCUM/keMGFSCNg3jkis= github.com/gin-contrib/timeout v1.1.0 h1:WAmWseo5gfBUbMrMJu5hJxDclehfSJUmK2wGwCC/EFw= github.com/gin-contrib/timeout v1.1.0/go.mod h1:NpRo4gd1Ad8ZQ4T6bQLVFDqiplCmPRs2nvfckxS2Fw4= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= @@ -168,6 +178,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= +github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= @@ -264,6 +276,8 @@ github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYW github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -427,6 +441,8 @@ go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc= golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= +golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -634,6 +650,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 06016d0c8865153467b599ad806a39c0f948224e Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Sat, 13 Sep 2025 18:19:14 +0800 Subject: [PATCH 17/19] =?UTF-8?q?:=20=E6=96=B0=E5=A2=9Enew=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E7=94=9F=E6=88=90=E9=A1=B9=E7=9B=AE=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/curd/curd.go | 51 ---- go.mod | 1 + go.sum | 2 + tool/cobra.go | 5 +- tool/curd/curd.go | 2 +- tool/curd/template/with_cache/example.tpl | 6 +- tool/curd/template/with_cache/var.tpl | 11 + tool/helloworld/api/local/v1/hello.pb.go | 182 +++++++++++++++ tool/helloworld/api/local/v1/hello.proto | 16 ++ tool/helloworld/api/local/v1/hello_grpc.pb.go | 121 ++++++++++ tool/helloworld/cmd/main.go | 26 +++ tool/helloworld/configs/config.yaml | 15 ++ tool/helloworld/configs/load.go | 55 +++++ tool/helloworld/explain.md | 17 ++ tool/helloworld/go.mod | 13 ++ tool/helloworld/go.sum | 14 ++ .../internal/infrastructure/interceptor.go | 18 ++ .../internal/infrastructure/provider.go | 84 +++++++ .../internal/repository/Usermodel.go | 33 +++ .../internal/repository/Usermodel_gen.go | 218 ++++++++++++++++++ tool/helloworld/internal/repository/model.go | 6 + .../internal/repository/provider.go | 9 + tool/helloworld/internal/repository/var.go | 20 ++ tool/helloworld/internal/server/provider.go | 7 + tool/helloworld/internal/server/register.go | 17 ++ tool/helloworld/internal/service/hello.go | 25 ++ tool/helloworld/internal/service/provider.go | 7 + tool/helloworld/internal/wire/wire.go | 23 ++ tool/helloworld/internal/wire/wire_gen.go | 40 ++++ tool/new/create/create.go | 208 +++++++++++++++++ tool/new/new.go | 25 ++ tool/new/new_test.go | 20 ++ tool/new/template/cmd/main.go.tpl | 26 +++ tool/new/template/configs/config.yaml.tpl | 15 ++ tool/new/template/configs/load.go.tpl | 55 +++++ tool/new/template/explain.md.tpl | 17 ++ tool/new/template/go.mod.tpl | 13 ++ tool/new/template/go.sum.tpl | 14 ++ .../infrastructure/interceptor.go.tpl | 18 ++ .../template/infrastructure/provider.go.tpl | 84 +++++++ tool/new/template/local/hello.pb.go.tpl | 182 +++++++++++++++ tool/new/template/local/hello.proto.tpl | 16 ++ tool/new/template/local/hello_grpc.pb.go.tpl | 121 ++++++++++ tool/new/template/repository/Usermodel.go.tpl | 33 +++ .../template/repository/Usermodel_gen.go.tpl | 218 ++++++++++++++++++ tool/new/template/repository/model.go.tpl | 6 + tool/new/template/repository/provider.go.tpl | 9 + tool/new/template/repository/var.go.tpl | 20 ++ tool/new/template/server/provider.go.tpl | 7 + tool/new/template/server/register.go.tpl | 17 ++ tool/new/template/service/hello.go.tpl | 25 ++ tool/new/template/service/provider.go.tpl | 7 + tool/new/template/wire/wire.go.tpl | 23 ++ tool/new/template/wire/wire_gen.go.tpl | 40 ++++ 54 files changed, 2206 insertions(+), 57 deletions(-) delete mode 100644 example/curd/curd.go create mode 100644 tool/helloworld/api/local/v1/hello.pb.go create mode 100644 tool/helloworld/api/local/v1/hello.proto create mode 100644 tool/helloworld/api/local/v1/hello_grpc.pb.go create mode 100644 tool/helloworld/cmd/main.go create mode 100644 tool/helloworld/configs/config.yaml create mode 100644 tool/helloworld/configs/load.go create mode 100644 tool/helloworld/explain.md create mode 100644 tool/helloworld/go.mod create mode 100644 tool/helloworld/go.sum create mode 100644 tool/helloworld/internal/infrastructure/interceptor.go create mode 100644 tool/helloworld/internal/infrastructure/provider.go create mode 100644 tool/helloworld/internal/repository/Usermodel.go create mode 100644 tool/helloworld/internal/repository/Usermodel_gen.go create mode 100644 tool/helloworld/internal/repository/model.go create mode 100644 tool/helloworld/internal/repository/provider.go create mode 100644 tool/helloworld/internal/repository/var.go create mode 100644 tool/helloworld/internal/server/provider.go create mode 100644 tool/helloworld/internal/server/register.go create mode 100644 tool/helloworld/internal/service/hello.go create mode 100644 tool/helloworld/internal/service/provider.go create mode 100644 tool/helloworld/internal/wire/wire.go create mode 100644 tool/helloworld/internal/wire/wire_gen.go create mode 100644 tool/new/create/create.go create mode 100644 tool/new/new.go create mode 100644 tool/new/new_test.go create mode 100644 tool/new/template/cmd/main.go.tpl create mode 100644 tool/new/template/configs/config.yaml.tpl create mode 100644 tool/new/template/configs/load.go.tpl create mode 100644 tool/new/template/explain.md.tpl create mode 100644 tool/new/template/go.mod.tpl create mode 100644 tool/new/template/go.sum.tpl create mode 100644 tool/new/template/infrastructure/interceptor.go.tpl create mode 100644 tool/new/template/infrastructure/provider.go.tpl create mode 100644 tool/new/template/local/hello.pb.go.tpl create mode 100644 tool/new/template/local/hello.proto.tpl create mode 100644 tool/new/template/local/hello_grpc.pb.go.tpl create mode 100644 tool/new/template/repository/Usermodel.go.tpl create mode 100644 tool/new/template/repository/Usermodel_gen.go.tpl create mode 100644 tool/new/template/repository/model.go.tpl create mode 100644 tool/new/template/repository/provider.go.tpl create mode 100644 tool/new/template/repository/var.go.tpl create mode 100644 tool/new/template/server/provider.go.tpl create mode 100644 tool/new/template/server/register.go.tpl create mode 100644 tool/new/template/service/hello.go.tpl create mode 100644 tool/new/template/service/provider.go.tpl create mode 100644 tool/new/template/wire/wire.go.tpl create mode 100644 tool/new/template/wire/wire_gen.go.tpl diff --git a/example/curd/curd.go b/example/curd/curd.go deleted file mode 100644 index b7802c0..0000000 --- a/example/curd/curd.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "context" - "fmt" - "github.com/muxi-Infra/muxi-micro/pkg/logger" - "github.com/muxi-Infra/muxi-micro/pkg/logger/zapx" - "github.com/muxi-Infra/muxi-micro/tool/curd/example" - "log" - "time" -) - -func main() { - DBdsn := "your db dsn" - redisAddr := "your redis addr" - redisPassword := "your redis password" - redisDB := 0 - // 缓存持续时间 - ttlForCache := 5 * time.Second - // 异步设置缓存时间 - ttlForSet := 5 * time.Second - // 日志记录 redis 错误 - l := zapx.NewDefaultZapLogger("./logs", logger.EnvTest) - instance, err := example.NewUserModels( - DBdsn, - redisAddr, - redisPassword, - redisDB, - ttlForCache, - ttlForSet, - l, - ) - if err != nil { - log.Fatal(err) - } - //user := example.User{ - // Id: 7, - // Username: "example3", - // Password: "123456", - // Mobile: "example111", - //} - //_ = instance.Create(context.Background(), &user) - //_ = instance.Update(context.Background(), &user) - //_ = instance.Delete(context.Background(), 7) - //value, err := instance.FindOne(context.Background(), 3) - value, err := instance.FindByMobile(context.Background(), "123456") - if err != nil { - log.Fatal(err) - } - fmt.Println(value) -} diff --git a/go.mod b/go.mod index fd7883f..b2e239c 100644 --- a/go.mod +++ b/go.mod @@ -80,6 +80,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/google/wire v0.7.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index 4cdceaf..2443824 100644 --- a/go.sum +++ b/go.sum @@ -230,6 +230,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= +github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= diff --git a/tool/cobra.go b/tool/cobra.go index 7f701b6..aec7ceb 100644 --- a/tool/cobra.go +++ b/tool/cobra.go @@ -2,6 +2,7 @@ package main import ( "github.com/muxi-Infra/muxi-micro/tool/curd" + "github.com/muxi-Infra/muxi-micro/tool/new" "github.com/spf13/cobra" ) @@ -11,8 +12,8 @@ func main() { Short: "muxi-micro 总命令", } - curdCmd := curd.InitCurdCobra() - muxiCmd.AddCommand(curdCmd) + muxiCmd.AddCommand(curd.InitCurdCobra()) + muxiCmd.AddCommand(new.InitNewCobra()) _ = muxiCmd.Execute() } diff --git a/tool/curd/curd.go b/tool/curd/curd.go index 8d161e6..265b7fc 100644 --- a/tool/curd/curd.go +++ b/tool/curd/curd.go @@ -47,7 +47,7 @@ func InitCurdCobra() *cobra.Command { }, } - curdCmd.Flags().String("package", "model", "生成文件的包名") + curdCmd.Flags().String("package", "repository", "生成文件的包名") curdCmd.Flags().String("dir", ".", "model文件以及文件生成目录") curdCmd.Flags().Bool("cache", false, "是否开启缓存") curdCmd.Flags().Bool("cover", false, "是否覆盖除 _gen.go 外的另外两个文件") diff --git a/tool/curd/template/with_cache/example.tpl b/tool/curd/template/with_cache/example.tpl index 491980d..03b5fa0 100644 --- a/tool/curd/template/with_cache/example.tpl +++ b/tool/curd/template/with_cache/example.tpl @@ -18,14 +18,14 @@ type Extra{{.ModelName}}Exec struct { *{{.ModelName}}Exec } -func New{{.ModelName}}Models(DBdsn, redisAddr, redisPassword string, number int, ttlForCache, ttlForSet time.Duration, l logger.Logger) ({{.ModelName}}Models, error) { +func New{{.ModelName}}Models(DBdsn string, Cache *CacheStruct) ({{.ModelName}}Models, error) { db, err := sql.ConnectDB(DBdsn, {{.ModelName}}{}) if err != nil { return nil, err } - cache := sql.ConnectCache(redisAddr, redisPassword, number, ttlForCache, ttlForSet) + cache := sql.ConnectCache(Cache.RedisAddr, Cache.RedisPassword, Cache.Number, Cache.TtlForCache, Cache.TtlForSet) - instance := New{{.ModelName}}Model(db, cache, l) + instance := New{{.ModelName}}Model(db, cache, Cache.Log) return &Extra{{.ModelName}}Exec{ instance, diff --git a/tool/curd/template/with_cache/var.tpl b/tool/curd/template/with_cache/var.tpl index 59f2ea7..87f7f0b 100644 --- a/tool/curd/template/with_cache/var.tpl +++ b/tool/curd/template/with_cache/var.tpl @@ -2,9 +2,20 @@ package {{.PackageName}} import ( + "github.com/muxi-Infra/muxi-micro/pkg/logger" "github.com/muxi-Infra/muxi-micro/pkg/sql" + "time" ) +type CacheStruct struct { + RedisAddr string + RedisPassword string + Number int + TtlForCache time.Duration + TtlForSet time.Duration + Log logger.Logger +} + const CacheNotFound = sql.CacheNotFound var DBNotFound = sql.DBNotFound diff --git a/tool/helloworld/api/local/v1/hello.pb.go b/tool/helloworld/api/local/v1/hello.pb.go new file mode 100644 index 0000000..10d92f5 --- /dev/null +++ b/tool/helloworld/api/local/v1/hello.pb.go @@ -0,0 +1,182 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v3.19.4 +// source: hello.proto + +package v1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type HelloRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HelloRequest) Reset() { + *x = HelloRequest{} + mi := &file_hello_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HelloRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloRequest) ProtoMessage() {} + +func (x *HelloRequest) ProtoReflect() protoreflect.Message { + mi := &file_hello_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead. +func (*HelloRequest) Descriptor() ([]byte, []int) { + return file_hello_proto_rawDescGZIP(), []int{0} +} + +func (x *HelloRequest) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +type HelloResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Code int64 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HelloResponse) Reset() { + *x = HelloResponse{} + mi := &file_hello_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HelloResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloResponse) ProtoMessage() {} + +func (x *HelloResponse) ProtoReflect() protoreflect.Message { + mi := &file_hello_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HelloResponse.ProtoReflect.Descriptor instead. +func (*HelloResponse) Descriptor() ([]byte, []int) { + return file_hello_proto_rawDescGZIP(), []int{1} +} + +func (x *HelloResponse) GetCode() int64 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *HelloResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_hello_proto protoreflect.FileDescriptor + +const file_hello_proto_rawDesc = "" + + "\n" + + "\vhello.proto\"*\n" + + "\fHelloRequest\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\"=\n" + + "\rHelloResponse\x12\x12\n" + + "\x04code\x18\x01 \x01(\x03R\x04code\x12\x18\n" + + "\amessage\x18\x02 \x01(\tR\amessage26\n" + + "\fHelloService\x12&\n" + + "\x05Hello\x12\r.HelloRequest\x1a\x0e.HelloResponseB\x06Z\x04./v1b\x06proto3" + +var ( + file_hello_proto_rawDescOnce sync.Once + file_hello_proto_rawDescData []byte +) + +func file_hello_proto_rawDescGZIP() []byte { + file_hello_proto_rawDescOnce.Do(func() { + file_hello_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_hello_proto_rawDesc), len(file_hello_proto_rawDesc))) + }) + return file_hello_proto_rawDescData +} + +var file_hello_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_hello_proto_goTypes = []any{ + (*HelloRequest)(nil), // 0: HelloRequest + (*HelloResponse)(nil), // 1: HelloResponse +} +var file_hello_proto_depIdxs = []int32{ + 0, // 0: HelloService.Hello:input_type -> HelloRequest + 1, // 1: HelloService.Hello:output_type -> HelloResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_hello_proto_init() } +func file_hello_proto_init() { + if File_hello_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_hello_proto_rawDesc), len(file_hello_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_hello_proto_goTypes, + DependencyIndexes: file_hello_proto_depIdxs, + MessageInfos: file_hello_proto_msgTypes, + }.Build() + File_hello_proto = out.File + file_hello_proto_goTypes = nil + file_hello_proto_depIdxs = nil +} diff --git a/tool/helloworld/api/local/v1/hello.proto b/tool/helloworld/api/local/v1/hello.proto new file mode 100644 index 0000000..6feb00f --- /dev/null +++ b/tool/helloworld/api/local/v1/hello.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +option go_package = "./v1"; + +message HelloRequest { + string username = 1; +} + +message HelloResponse { + int64 code = 1; + string message = 2; +} + +service HelloService { + rpc Hello(HelloRequest) returns (HelloResponse); +} \ No newline at end of file diff --git a/tool/helloworld/api/local/v1/hello_grpc.pb.go b/tool/helloworld/api/local/v1/hello_grpc.pb.go new file mode 100644 index 0000000..dbbdccb --- /dev/null +++ b/tool/helloworld/api/local/v1/hello_grpc.pb.go @@ -0,0 +1,121 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v3.19.4 +// source: hello.proto + +package v1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + HelloService_Hello_FullMethodName = "/HelloService/Hello" +) + +// HelloServiceClient is the client API for HelloService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type HelloServiceClient interface { + Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) +} + +type helloServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewHelloServiceClient(cc grpc.ClientConnInterface) HelloServiceClient { + return &helloServiceClient{cc} +} + +func (c *helloServiceClient) Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(HelloResponse) + err := c.cc.Invoke(ctx, HelloService_Hello_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// HelloServiceServer is the server API for HelloService service. +// All implementations must embed UnimplementedHelloServiceServer +// for forward compatibility. +type HelloServiceServer interface { + Hello(context.Context, *HelloRequest) (*HelloResponse, error) + mustEmbedUnimplementedHelloServiceServer() +} + +// UnimplementedHelloServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedHelloServiceServer struct{} + +func (UnimplementedHelloServiceServer) Hello(context.Context, *HelloRequest) (*HelloResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Hello not implemented") +} +func (UnimplementedHelloServiceServer) mustEmbedUnimplementedHelloServiceServer() {} +func (UnimplementedHelloServiceServer) testEmbeddedByValue() {} + +// UnsafeHelloServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to HelloServiceServer will +// result in compilation errors. +type UnsafeHelloServiceServer interface { + mustEmbedUnimplementedHelloServiceServer() +} + +func RegisterHelloServiceServer(s grpc.ServiceRegistrar, srv HelloServiceServer) { + // If the following call pancis, it indicates UnimplementedHelloServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&HelloService_ServiceDesc, srv) +} + +func _HelloService_Hello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HelloServiceServer).Hello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HelloService_Hello_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HelloServiceServer).Hello(ctx, req.(*HelloRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// HelloService_ServiceDesc is the grpc.ServiceDesc for HelloService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var HelloService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "HelloService", + HandlerType: (*HelloServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Hello", + Handler: _HelloService_Hello_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "hello.proto", +} diff --git a/tool/helloworld/cmd/main.go b/tool/helloworld/cmd/main.go new file mode 100644 index 0000000..874abaf --- /dev/null +++ b/tool/helloworld/cmd/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "helloworld/internal/infrastructure" + "helloworld/internal/wire" + "log" + "net" +) + +func main() { + grpcInstance, err := infrastructure.ProvideGrpcInstance() + if err != nil { + log.Fatal(err) + } + s, _, err := wire.WireApp() + if err != nil { + log.Fatal(err) + } + lis, err := net.Listen(grpcInstance.Net, grpcInstance.Addr) + if err != nil { + log.Fatal(err) + } + if err := s.Serve(lis); err != nil { + log.Fatal(err) + } +} diff --git a/tool/helloworld/configs/config.yaml b/tool/helloworld/configs/config.yaml new file mode 100644 index 0000000..89e4b63 --- /dev/null +++ b/tool/helloworld/configs/config.yaml @@ -0,0 +1,15 @@ +server: + grpc: + addr: 0.0.0.0:50051 + timeout: 5s +data: + mysql: + dsn: root:root@tcp(localhost:3306)/circle2?parseTime=true&charset=utf8mb4&loc=Local + redis: + addr: localhost:6379 + password: 123456 + num: 0 + read: 0.2s + write: 0.2s +log: + dir: ./logs diff --git a/tool/helloworld/configs/load.go b/tool/helloworld/configs/load.go new file mode 100644 index 0000000..e72e7d2 --- /dev/null +++ b/tool/helloworld/configs/load.go @@ -0,0 +1,55 @@ +package configs + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/config" + "sync" + "time" +) + +var ( + configOnce sync.Once + configInstance *Config + configErr error +) + +type Config struct { + Server struct { + Grpc struct { + Addr string `yaml:"addr"` + Network string `yaml:"network"` + Timeout time.Duration `yaml:"timeout"` + } `yaml:"grpc"` + } `yaml:"server"` + Data struct { + MySQL struct { + Dsn string `yaml:"dsn"` + } `yaml:"mysql"` + Redis struct { + Addr string `yaml:"addr"` + Password string `yaml:"password"` + Num int `yaml:"num"` + Read time.Duration `yaml:"read"` + Write time.Duration `yaml:"write"` + } `yaml:"redis"` + } `yaml:"data"` + Log struct { + Dir string `yaml:"dir"` + } `yaml:"log"` +} + +func LoadConfig() (*Config, error) { + configOnce.Do(func() { + cfg, err := config.NewLocalConfig(&Config{}, "../../configs/config.yaml") + if err != nil { + configErr = err + return + } + err = cfg.LoadData() + if err != nil { + configErr = err + return + } + configInstance = cfg.GetData().(*Config) + }) + return configInstance, configErr +} diff --git a/tool/helloworld/explain.md b/tool/helloworld/explain.md new file mode 100644 index 0000000..82e1329 --- /dev/null +++ b/tool/helloworld/explain.md @@ -0,0 +1,17 @@ +# 项目结构 +```gas +helloworld/ +├── api/ +│ ├── local/ 存放本地proto +│ │ └── v1/ +│ └── third_party/ 存放第三方proto +├── cmd/ 主函数所在地 +├── configs/ 读取配置 +└── internal/ + ├── infrastructure/ 基础设施层(提供DB,redisDB,logger等,中间件等) + ├── repository/ 仓储层(配合自动curd使用) + ├── server/ grpc注册 + ├── service/ 服务层(具体业务逻辑) + └── wire/ wire依赖注入 +``` + diff --git a/tool/helloworld/go.mod b/tool/helloworld/go.mod new file mode 100644 index 0000000..decd624 --- /dev/null +++ b/tool/helloworld/go.mod @@ -0,0 +1,13 @@ +module helloworld + +go 1.24.5 + +require ( + github.com/google/wire v0.7.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/grpc v1.75.1 // indirect + google.golang.org/protobuf v1.36.6 // indirect +) diff --git a/tool/helloworld/go.sum b/tool/helloworld/go.sum new file mode 100644 index 0000000..9464001 --- /dev/null +++ b/tool/helloworld/go.sum @@ -0,0 +1,14 @@ +github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= +github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI= +google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= diff --git a/tool/helloworld/internal/infrastructure/interceptor.go b/tool/helloworld/internal/infrastructure/interceptor.go new file mode 100644 index 0000000..e6afa61 --- /dev/null +++ b/tool/helloworld/internal/infrastructure/interceptor.go @@ -0,0 +1,18 @@ +package infrastructure + +import ( + "context" + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "google.golang.org/grpc" +) + +func (g *Grpc) ServerInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + resp, err = handler(ctx, req) + if err != nil { + str := g.Addr + " 发生错误" + g.logger.Error(str, logger.Error(err)) + } + return resp, err + } +} diff --git a/tool/helloworld/internal/infrastructure/provider.go b/tool/helloworld/internal/infrastructure/provider.go new file mode 100644 index 0000000..04c58d0 --- /dev/null +++ b/tool/helloworld/internal/infrastructure/provider.go @@ -0,0 +1,84 @@ +package infrastructure + +import ( + "errors" + "github.com/google/wire" + "helloworld/configs" + "helloworld/internal/repository" + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/logger/zapx" + "sync" + "time" +) + +var ProviderSet = wire.NewSet( + ProvideGrpcInstance, + ProvideDB, + ProvideCache, +) + +type Grpc struct { + logger logger.Logger + Addr string + Timeout time.Duration + Net string +} + +var ( + Err error + Once sync.Once + instance *Grpc +) + +var MissingAddrErr = errors.New("you should add a address(like 0.0.0.0:50051) on the configs") + +func ProvideGrpcInstance() (*Grpc, error) { + Once.Do(func() { + cfg, err := configs.LoadConfig() + if err != nil { + Err = err + return + } + if cfg.Server.Grpc.Addr == "" { + Err = MissingAddrErr + return + } + if cfg.Server.Grpc.Timeout == 0 { + cfg.Server.Grpc.Timeout = 10 * time.Second + } + if cfg.Server.Grpc.Network == "" { + cfg.Server.Grpc.Network = "tcp" + } + instance = &Grpc{ + logger: zapx.NewDefaultZapLogger(cfg.Log.Dir, logger.EnvTest), + Addr: cfg.Server.Grpc.Addr, + Timeout: cfg.Server.Grpc.Timeout, + Net: cfg.Server.Grpc.Network, + } + }) + return instance, Err +} + +func ProvideDB() (string, error) { + cfg, err := configs.LoadConfig() + if err != nil { + return "", err + } + return cfg.Data.MySQL.Dsn, nil +} + +func ProvideCache(g *Grpc) (*repository.CacheStruct, error) { + cfg, err := configs.LoadConfig() + if err != nil { + return nil, err + } + data := cfg.Data.Redis + return &repository.CacheStruct{ + RedisAddr: data.Addr, + RedisPassword: data.Password, + Number: data.Num, + TtlForCache: data.Read, + TtlForSet: data.Write, + Log: g.logger, + }, nil +} diff --git a/tool/helloworld/internal/repository/Usermodel.go b/tool/helloworld/internal/repository/Usermodel.go new file mode 100644 index 0000000..14df834 --- /dev/null +++ b/tool/helloworld/internal/repository/Usermodel.go @@ -0,0 +1,33 @@ +package repository + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/sql" +) + +var _ UserModels = (*ExtraUserExec)(nil) + +type UserModels interface { + UserModel + // 可以在这里添加额外的方法接口 +} + +type ExtraUserExec struct { + *UserExec +} + +func NewUserModels(DBdsn string, Cache *CacheStruct) (UserModels, error) { + db, err := sql.ConnectDB(DBdsn, User{}) + if err != nil { + return nil, err + } + cache := sql.ConnectCache(Cache.RedisAddr, Cache.RedisPassword, Cache.Number, Cache.TtlForCache, Cache.TtlForSet) + + instance := NewUserModel(db, cache, Cache.Log) + + return &ExtraUserExec{ + instance, + }, nil +} + +// 可以在这里添加额外的方法实现 +// func (e *ExtraUserExec) ... diff --git a/tool/helloworld/internal/repository/Usermodel_gen.go b/tool/helloworld/internal/repository/Usermodel_gen.go new file mode 100644 index 0000000..5c22be5 --- /dev/null +++ b/tool/helloworld/internal/repository/Usermodel_gen.go @@ -0,0 +1,218 @@ +// Code generated by muxi curd. DO NOT EDIT. + +package repository + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/sql" + "golang.org/x/sync/singleflight" + "gorm.io/gorm" +) + +const ( + cacheUserUsernamePrefix = "cache:User:Username:" + cacheUserIdPrefix = "cache:User:Id:" +) + +var group singleflight.Group + +type UserModel interface { + Create(ctx context.Context, data *User) error + FindOne(ctx context.Context, id int64) (*User, error) + FindByUsername(ctx context.Context, Username string) (*[]User, error) + Update(ctx context.Context, data *User) error + Delete(ctx context.Context, id int64) error +} + +type UserExec struct { + exec *sql.Execute + cacheExec *sql.CacheExecute + logger logger.Logger +} + +func NewUserModel(db *gorm.DB, cache *sql.CacheExecute, logger logger.Logger) *UserExec { + exec := sql.NewExecute(User{}, db) + return &UserExec{ + exec: exec, + cacheExec: cache, + logger: logger, + } +} + +// 序列化 +func UnMarshalJSON(s string, model *User) error { + return json.Unmarshal([]byte(s), model) +} + +func UnMarshalString(s string, model *[]int64) error { + return json.Unmarshal([]byte(s), model) +} + +func (u *UserExec) Create(ctx context.Context, data *User) error { + err := u.exec.Create(ctx, data) + if err != nil { + return err + } + go u.DelCache(ctx, data) + return nil +} + +func (u *UserExec) FindOne(ctx context.Context, Id int64) (*User, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, Id) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + datacache := u.Get(ctx, cachestr) + if datacache != nil { + return datacache, nil + } + var data User + u.exec.AddWhere("Id = ?", Id) + err := u.exec.Find(ctx, &data) + if err != nil { + return nil, err + } + if data.Id == 0 { + return nil, DBNotFound + } + go u.Set(cachestr, &data) + return &data, nil + }) + if result == nil { + return nil, err + } + return result.(*User), err +} + +func (u *UserExec) FindByUsername(ctx context.Context, Username string) (*[]User, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, Username) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + datascache := u.GetMany(ctx, cacheval) + if datascache != nil { + return datascache, nil + } + var datas []User + u.exec.AddWhere("Username = ?", Username) + err = u.exec.Find(ctx, &datas) + if err != nil { + return nil, err + } + if len(datas) == 0 { + return nil, DBNotFound + } + go u.SetMany(cachestr, &datas) + return &datas, nil + }) + if result == nil { + return nil, err + } + return result.(*[]User), err +} + +func (u *UserExec) Update(ctx context.Context, data *User) error { + u.exec.AddWhere("id = ?", data.Id) + err := u.exec.Update(ctx, data) + if err != nil { + return err + } + go u.DelCache(ctx, data) + return nil +} + +func (u *UserExec) Delete(ctx context.Context, id int64) error { + var data User + d, err := u.FindOne(ctx, id) + if err != nil { + return err + } + data = *d + err = u.exec.Delete(ctx, &data) + if err != nil { + return err + } + go u.DelCache(ctx, &data) + return nil +} + +// cache +func (u *UserExec) DelCache(ctx context.Context, model *User) { + err := u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserIdPrefix, model.Id), ctx) + if err != nil { + u.logger.Error("主键缓存删除失败", logger.Int64("Id", model.Id),logger.Error(err)) + } + err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserUsernamePrefix, model.Username), ctx) + if err != nil { + u.logger.Warn("非主键缓存删除失败", logger.String("Username", model.Username),logger.Error(err)) + } +} + +func (u *UserExec) Get(ctx context.Context, cachestr string) *User { + var data User + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + if err == nil { + err := UnMarshalJSON(cacheval, &data) + if err != nil { + u.logger.Warn("Json 序列化出错", logger.Error(err)) + return nil + } + return &data + } + if !errors.Is(err, CacheNotFound) { + u.logger.Warn("主键缓存获取失败", logger.Error(err)) + return nil + } + return nil +} + +func (u *UserExec) GetMany(ctx context.Context, cachestr string) *[]User { + var datas []User + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + if err == nil { + var key []int64 + err := UnMarshalString(cacheval, &key) + if err != nil { + u.logger.Warn("Json 序列化出错", logger.Error(err)) + return nil + } + for _, c := range key { + data, err := u.FindOne(ctx, c) + if err != nil { + return nil + } + datas = append(datas, *data) + } + return &datas + } + if !errors.Is(err, CacheNotFound) { + u.logger.Warn("非主键缓存获取失败", logger.Error(err)) + return nil + } + return nil +} + +func (u *UserExec) Set(cachestr string, data *User) { + ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) + err := u.cacheExec.SetCache(cachestr, ctx, data) + if err != nil { + u.logger.Warn("主键缓存设置失败", logger.Error(err)) + } + cancel() +} + +func (u *UserExec) SetMany(cachestr string, data *[]User) { + ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) + var key []int64 + for _, v := range *data { + key = append(key, v.Id) + cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, v.Id) + u.Set(cachestr, &v) + } + err := u.cacheExec.SetCache(cachestr, ctx, &key) + if err != nil { + u.logger.Warn("非主键缓存设置失败", logger.Error(err)) + } + cancel() +} \ No newline at end of file diff --git a/tool/helloworld/internal/repository/model.go b/tool/helloworld/internal/repository/model.go new file mode 100644 index 0000000..c304bb2 --- /dev/null +++ b/tool/helloworld/internal/repository/model.go @@ -0,0 +1,6 @@ +package repository + +type User struct { + Id int64 `gorm:"primaryKey;autoIncrement"` + Username string `gorm:"size:50;unique;"` +} diff --git a/tool/helloworld/internal/repository/provider.go b/tool/helloworld/internal/repository/provider.go new file mode 100644 index 0000000..ce370e9 --- /dev/null +++ b/tool/helloworld/internal/repository/provider.go @@ -0,0 +1,9 @@ +package repository + +import ( + "github.com/google/wire" +) + +var ProviderSet = wire.NewSet( + NewUserModels, +) diff --git a/tool/helloworld/internal/repository/var.go b/tool/helloworld/internal/repository/var.go new file mode 100644 index 0000000..71ae962 --- /dev/null +++ b/tool/helloworld/internal/repository/var.go @@ -0,0 +1,20 @@ +package repository + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/sql" + "time" +) + +type CacheStruct struct { + RedisAddr string + RedisPassword string + Number int + TtlForCache time.Duration + TtlForSet time.Duration + Log logger.Logger +} + +const CacheNotFound = sql.CacheNotFound + +var DBNotFound = sql.DBNotFound diff --git a/tool/helloworld/internal/server/provider.go b/tool/helloworld/internal/server/provider.go new file mode 100644 index 0000000..9e465dc --- /dev/null +++ b/tool/helloworld/internal/server/provider.go @@ -0,0 +1,7 @@ +package server + +import "github.com/google/wire" + +var ProviderSet = wire.NewSet( + NewGRPCServer, +) diff --git a/tool/helloworld/internal/server/register.go b/tool/helloworld/internal/server/register.go new file mode 100644 index 0000000..31d75a4 --- /dev/null +++ b/tool/helloworld/internal/server/register.go @@ -0,0 +1,17 @@ +package server + +import ( + pb "helloworld/api/local/v1" + "helloworld/internal/infrastructure" + "helloworld/internal/service" + "google.golang.org/grpc" +) + +func NewGRPCServer(helloService *service.HelloService, g *infrastructure.Grpc) *grpc.Server { + opts := []grpc.ServerOption{ + grpc.UnaryInterceptor(g.ServerInterceptor()), + } + s := grpc.NewServer(opts...) + pb.RegisterHelloServiceServer(s, helloService) + return s +} diff --git a/tool/helloworld/internal/service/hello.go b/tool/helloworld/internal/service/hello.go new file mode 100644 index 0000000..c730f5d --- /dev/null +++ b/tool/helloworld/internal/service/hello.go @@ -0,0 +1,25 @@ +package service + +import ( + "context" + pb "helloworld/api/local/v1" + "helloworld/internal/repository" +) + +type HelloService struct { + pb.UnimplementedHelloServiceServer + helloRepo repository.UserModels +} + +func NewHelloService(helloRepo repository.UserModels) *HelloService { + return &HelloService{ + helloRepo: helloRepo, + } +} + +func (s *HelloService) Hello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) { + return &pb.HelloResponse{ + Message: "Hello " + req.Username, + Code: 200, + }, nil +} diff --git a/tool/helloworld/internal/service/provider.go b/tool/helloworld/internal/service/provider.go new file mode 100644 index 0000000..7186784 --- /dev/null +++ b/tool/helloworld/internal/service/provider.go @@ -0,0 +1,7 @@ +package service + +import "github.com/google/wire" + +var ProviderSet = wire.NewSet( + NewHelloService, +) \ No newline at end of file diff --git a/tool/helloworld/internal/wire/wire.go b/tool/helloworld/internal/wire/wire.go new file mode 100644 index 0000000..dea8409 --- /dev/null +++ b/tool/helloworld/internal/wire/wire.go @@ -0,0 +1,23 @@ +//go:build wireinject + +package wire + +import ( + "github.com/google/wire" + "helloworld/internal/infrastructure" + "helloworld/internal/repository" + "helloworld/internal/server" + "helloworld/internal/service" + "google.golang.org/grpc" +) + +func WireApp() (*grpc.Server, func(), error) { + panic(wire.Build( + infrastructure.ProvideGrpcInstance, + infrastructure.ProvideDB, + infrastructure.ProvideCache, + repository.ProviderSet, + service.ProviderSet, + server.ProviderSet, + )) +} diff --git a/tool/helloworld/internal/wire/wire_gen.go b/tool/helloworld/internal/wire/wire_gen.go new file mode 100644 index 0000000..a6204ac --- /dev/null +++ b/tool/helloworld/internal/wire/wire_gen.go @@ -0,0 +1,40 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate go run -mod=mod github.com/google/wire/cmd/wire +//go:build !wireinject +// +build !wireinject + +package wire + +import ( + "helloworld/internal/infrastructure" + "helloworld/internal/repository" + "helloworld/internal/server" + "helloworld/internal/service" + "google.golang.org/grpc" +) + +// Injectors from wire.go: + +func WireApp() (*grpc.Server, func(), error) { + string2, err := infrastructure.ProvideDB() + if err != nil { + return nil, nil, err + } + infrastructureGrpc, err := infrastructure.ProvideGrpcInstance() + if err != nil { + return nil, nil, err + } + cacheStruct, err := infrastructure.ProvideCache(infrastructureGrpc) + if err != nil { + return nil, nil, err + } + userModels, err := repository.NewUserModels(string2, cacheStruct) + if err != nil { + return nil, nil, err + } + helloService := service.NewHelloService(userModels) + grpcServer := server.NewGRPCServer(helloService, infrastructureGrpc) + return grpcServer, func() { + }, nil +} diff --git a/tool/new/create/create.go b/tool/new/create/create.go new file mode 100644 index 0000000..e82697b --- /dev/null +++ b/tool/new/create/create.go @@ -0,0 +1,208 @@ +package create + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" +) + +func CreateDocument(rootDir string) error { + dirs := []string{ + filepath.Join(rootDir, "helloworld", "api", "local", "v1"), + filepath.Join(rootDir, "helloworld", "api", "third_party"), + filepath.Join(rootDir, "helloworld", "cmd"), + filepath.Join(rootDir, "helloworld", "configs"), + filepath.Join(rootDir, "helloworld", "internal", "infrastructure"), + filepath.Join(rootDir, "helloworld", "internal", "repository"), + filepath.Join(rootDir, "helloworld", "internal", "server"), + filepath.Join(rootDir, "helloworld", "internal", "service"), + filepath.Join(rootDir, "helloworld", "internal", "wire"), + } + for _, dir := range dirs { + err := os.MkdirAll(dir, 0755) + if err != nil { + return err + } + } + return nil +} + +func CreateCmd(rootDir string) error { + path := []string{"main.go"} + for _, p := range path { + templatePath := filepath.Join("new", "template", "cmd", p+".tpl") + templateContent, err := ioutil.ReadFile(templatePath) + if err != nil { + return err + } + createPath := filepath.Join(rootDir, "helloworld", "cmd", p) + if err := ioutil.WriteFile(createPath, templateContent, 0644); err != nil { + return err + } + } + return nil +} + +func CreateConfigs(rootDir string) error { + path := []string{"config.yaml", "load.go"} + for _, p := range path { + templatePath := filepath.Join("new", "template", "configs", p+".tpl") + templateContent, err := ioutil.ReadFile(templatePath) + if err != nil { + return err + } + createPath := filepath.Join(rootDir, "helloworld", "configs", p) + if err := ioutil.WriteFile(createPath, templateContent, 0644); err != nil { + return err + } + } + return nil +} + +func CreateInfrastructure(rootDir string) error { + path := []string{"interceptor.go", "provider.go"} + for _, p := range path { + templatePath := filepath.Join("new", "template", "infrastructure", p+".tpl") + templateContent, err := ioutil.ReadFile(templatePath) + if err != nil { + return err + } + createPath := filepath.Join(rootDir, "helloworld", "internal", "infrastructure", p) + if err := ioutil.WriteFile(createPath, templateContent, 0644); err != nil { + fmt.Println(666) + return err + } + } + return nil +} + +func CreateLocal(rootDir string) error { + path := []string{"hello.pb.go", "hello.proto", "hello_grpc.pb.go"} + for _, p := range path { + templatePath := filepath.Join("new", "template", "local", p+".tpl") + templateContent, err := ioutil.ReadFile(templatePath) + if err != nil { + return err + } + createPath := filepath.Join(rootDir, "helloworld", "api", "local", "v1", p) + if err := ioutil.WriteFile(createPath, templateContent, 0644); err != nil { + return err + } + } + return nil +} + +func CreateRepository(rootDir string) error { + paths := []string{"model.go", "provider.go", "Usermodel.go", "Usermodel_gen.go", "var.go"} + for _, p := range paths { + templatePath := filepath.Join("new", "template", "repository", p+".tpl") + templateContent, err := ioutil.ReadFile(templatePath) + if err != nil { + return err + } + createPath := filepath.Join(rootDir, "helloworld", "internal", "repository", p) + if err := ioutil.WriteFile(createPath, templateContent, 0644); err != nil { + return err + } + } + return nil +} + +func CreateServer(rootDir string) error { + paths := []string{"provider.go", "register.go"} + for _, p := range paths { + templatePath := filepath.Join("new", "template", "server", p+".tpl") + templateContent, err := ioutil.ReadFile(templatePath) + if err != nil { + return err + } + createPath := filepath.Join(rootDir, "helloworld", "internal", "server", p) + if err := ioutil.WriteFile(createPath, templateContent, 0644); err != nil { + return err + } + } + return nil +} + +func CreateService(rootDir string) error { + paths := []string{"hello.go", "provider.go"} + for _, p := range paths { + templatePath := filepath.Join("new", "template", "service", p+".tpl") + templateContent, err := ioutil.ReadFile(templatePath) + if err != nil { + return err + } + createPath := filepath.Join(rootDir, "helloworld", "internal", "service", p) + if err := ioutil.WriteFile(createPath, templateContent, 0644); err != nil { + return err + } + } + return nil +} + +func CreateWire(rootDir string) error { + paths := []string{"wire.go", "wire_gen.go"} + for _, p := range paths { + templatePath := filepath.Join("new", "template", "wire", p+".tpl") + templateContent, err := ioutil.ReadFile(templatePath) + if err != nil { + return err + } + createPath := filepath.Join(rootDir, "helloworld", "internal", "wire", p) + if err := ioutil.WriteFile(createPath, templateContent, 0644); err != nil { + return err + } + } + return nil +} + +func CreateExplain(rootDir string) error { + paths := []string{"explain.md", "go.mod", "go.sum"} + for _, p := range paths { + templatePath := filepath.Join("new", "template", p+".tpl") + templateContent, err := ioutil.ReadFile(templatePath) + if err != nil { + return err + } + createPath := filepath.Join(rootDir, "helloworld", p) + if err := ioutil.WriteFile(createPath, templateContent, 0644); err != nil { + return err + } + } + return nil +} + +func CreateAll(rootDir string) error { + if err := CreateDocument(rootDir); err != nil { + return err + } + if err := CreateCmd(rootDir); err != nil { + return err + } + if err := CreateConfigs(rootDir); err != nil { + return err + } + if err := CreateInfrastructure(rootDir); err != nil { + return err + } + if err := CreateLocal(rootDir); err != nil { + return err + } + if err := CreateRepository(rootDir); err != nil { + return err + } + if err := CreateServer(rootDir); err != nil { + return err + } + if err := CreateService(rootDir); err != nil { + return err + } + if err := CreateWire(rootDir); err != nil { + return err + } + if err := CreateExplain(rootDir); err != nil { + return err + } + return nil +} diff --git a/tool/new/new.go b/tool/new/new.go new file mode 100644 index 0000000..27bc837 --- /dev/null +++ b/tool/new/new.go @@ -0,0 +1,25 @@ +package new + +import ( + "github.com/muxi-Infra/muxi-micro/tool/new/create" + "github.com/spf13/cobra" +) + +func InitNewCobra() *cobra.Command { + // new 子命令 + var newCmd = &cobra.Command{ + Use: "new", + Short: "new 项目模板构建", + RunE: func(cmd *cobra.Command, args []string) error { + dir, _ := cmd.Flags().GetString("dir") + if err := create.CreateAll(dir); err != nil { + return err + } + return nil + }, + } + + newCmd.Flags().String("dir", ".", "项目生成路径") + + return newCmd +} diff --git a/tool/new/new_test.go b/tool/new/new_test.go new file mode 100644 index 0000000..3008da4 --- /dev/null +++ b/tool/new/new_test.go @@ -0,0 +1,20 @@ +package new + +import ( + "github.com/stretchr/testify/assert" + "strings" + "testing" +) + +func TestNew(t *testing.T) { + t.Run("dir not exist", func(t *testing.T) { + newCmd := InitNewCobra() + var output strings.Builder + newCmd.SetOutput(&output) + newCmd.SetArgs([]string{ + "--dir", "test", + }) + err := newCmd.Execute() + assert.ErrorContains(t, err, "The system cannot find the path specified") + }) +} diff --git a/tool/new/template/cmd/main.go.tpl b/tool/new/template/cmd/main.go.tpl new file mode 100644 index 0000000..874abaf --- /dev/null +++ b/tool/new/template/cmd/main.go.tpl @@ -0,0 +1,26 @@ +package main + +import ( + "helloworld/internal/infrastructure" + "helloworld/internal/wire" + "log" + "net" +) + +func main() { + grpcInstance, err := infrastructure.ProvideGrpcInstance() + if err != nil { + log.Fatal(err) + } + s, _, err := wire.WireApp() + if err != nil { + log.Fatal(err) + } + lis, err := net.Listen(grpcInstance.Net, grpcInstance.Addr) + if err != nil { + log.Fatal(err) + } + if err := s.Serve(lis); err != nil { + log.Fatal(err) + } +} diff --git a/tool/new/template/configs/config.yaml.tpl b/tool/new/template/configs/config.yaml.tpl new file mode 100644 index 0000000..89e4b63 --- /dev/null +++ b/tool/new/template/configs/config.yaml.tpl @@ -0,0 +1,15 @@ +server: + grpc: + addr: 0.0.0.0:50051 + timeout: 5s +data: + mysql: + dsn: root:root@tcp(localhost:3306)/circle2?parseTime=true&charset=utf8mb4&loc=Local + redis: + addr: localhost:6379 + password: 123456 + num: 0 + read: 0.2s + write: 0.2s +log: + dir: ./logs diff --git a/tool/new/template/configs/load.go.tpl b/tool/new/template/configs/load.go.tpl new file mode 100644 index 0000000..e72e7d2 --- /dev/null +++ b/tool/new/template/configs/load.go.tpl @@ -0,0 +1,55 @@ +package configs + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/config" + "sync" + "time" +) + +var ( + configOnce sync.Once + configInstance *Config + configErr error +) + +type Config struct { + Server struct { + Grpc struct { + Addr string `yaml:"addr"` + Network string `yaml:"network"` + Timeout time.Duration `yaml:"timeout"` + } `yaml:"grpc"` + } `yaml:"server"` + Data struct { + MySQL struct { + Dsn string `yaml:"dsn"` + } `yaml:"mysql"` + Redis struct { + Addr string `yaml:"addr"` + Password string `yaml:"password"` + Num int `yaml:"num"` + Read time.Duration `yaml:"read"` + Write time.Duration `yaml:"write"` + } `yaml:"redis"` + } `yaml:"data"` + Log struct { + Dir string `yaml:"dir"` + } `yaml:"log"` +} + +func LoadConfig() (*Config, error) { + configOnce.Do(func() { + cfg, err := config.NewLocalConfig(&Config{}, "../../configs/config.yaml") + if err != nil { + configErr = err + return + } + err = cfg.LoadData() + if err != nil { + configErr = err + return + } + configInstance = cfg.GetData().(*Config) + }) + return configInstance, configErr +} diff --git a/tool/new/template/explain.md.tpl b/tool/new/template/explain.md.tpl new file mode 100644 index 0000000..82e1329 --- /dev/null +++ b/tool/new/template/explain.md.tpl @@ -0,0 +1,17 @@ +# 项目结构 +```gas +helloworld/ +├── api/ +│ ├── local/ 存放本地proto +│ │ └── v1/ +│ └── third_party/ 存放第三方proto +├── cmd/ 主函数所在地 +├── configs/ 读取配置 +└── internal/ + ├── infrastructure/ 基础设施层(提供DB,redisDB,logger等,中间件等) + ├── repository/ 仓储层(配合自动curd使用) + ├── server/ grpc注册 + ├── service/ 服务层(具体业务逻辑) + └── wire/ wire依赖注入 +``` + diff --git a/tool/new/template/go.mod.tpl b/tool/new/template/go.mod.tpl new file mode 100644 index 0000000..decd624 --- /dev/null +++ b/tool/new/template/go.mod.tpl @@ -0,0 +1,13 @@ +module helloworld + +go 1.24.5 + +require ( + github.com/google/wire v0.7.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/grpc v1.75.1 // indirect + google.golang.org/protobuf v1.36.6 // indirect +) diff --git a/tool/new/template/go.sum.tpl b/tool/new/template/go.sum.tpl new file mode 100644 index 0000000..9464001 --- /dev/null +++ b/tool/new/template/go.sum.tpl @@ -0,0 +1,14 @@ +github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= +github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI= +google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= diff --git a/tool/new/template/infrastructure/interceptor.go.tpl b/tool/new/template/infrastructure/interceptor.go.tpl new file mode 100644 index 0000000..e6afa61 --- /dev/null +++ b/tool/new/template/infrastructure/interceptor.go.tpl @@ -0,0 +1,18 @@ +package infrastructure + +import ( + "context" + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "google.golang.org/grpc" +) + +func (g *Grpc) ServerInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + resp, err = handler(ctx, req) + if err != nil { + str := g.Addr + " 发生错误" + g.logger.Error(str, logger.Error(err)) + } + return resp, err + } +} diff --git a/tool/new/template/infrastructure/provider.go.tpl b/tool/new/template/infrastructure/provider.go.tpl new file mode 100644 index 0000000..04c58d0 --- /dev/null +++ b/tool/new/template/infrastructure/provider.go.tpl @@ -0,0 +1,84 @@ +package infrastructure + +import ( + "errors" + "github.com/google/wire" + "helloworld/configs" + "helloworld/internal/repository" + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/logger/zapx" + "sync" + "time" +) + +var ProviderSet = wire.NewSet( + ProvideGrpcInstance, + ProvideDB, + ProvideCache, +) + +type Grpc struct { + logger logger.Logger + Addr string + Timeout time.Duration + Net string +} + +var ( + Err error + Once sync.Once + instance *Grpc +) + +var MissingAddrErr = errors.New("you should add a address(like 0.0.0.0:50051) on the configs") + +func ProvideGrpcInstance() (*Grpc, error) { + Once.Do(func() { + cfg, err := configs.LoadConfig() + if err != nil { + Err = err + return + } + if cfg.Server.Grpc.Addr == "" { + Err = MissingAddrErr + return + } + if cfg.Server.Grpc.Timeout == 0 { + cfg.Server.Grpc.Timeout = 10 * time.Second + } + if cfg.Server.Grpc.Network == "" { + cfg.Server.Grpc.Network = "tcp" + } + instance = &Grpc{ + logger: zapx.NewDefaultZapLogger(cfg.Log.Dir, logger.EnvTest), + Addr: cfg.Server.Grpc.Addr, + Timeout: cfg.Server.Grpc.Timeout, + Net: cfg.Server.Grpc.Network, + } + }) + return instance, Err +} + +func ProvideDB() (string, error) { + cfg, err := configs.LoadConfig() + if err != nil { + return "", err + } + return cfg.Data.MySQL.Dsn, nil +} + +func ProvideCache(g *Grpc) (*repository.CacheStruct, error) { + cfg, err := configs.LoadConfig() + if err != nil { + return nil, err + } + data := cfg.Data.Redis + return &repository.CacheStruct{ + RedisAddr: data.Addr, + RedisPassword: data.Password, + Number: data.Num, + TtlForCache: data.Read, + TtlForSet: data.Write, + Log: g.logger, + }, nil +} diff --git a/tool/new/template/local/hello.pb.go.tpl b/tool/new/template/local/hello.pb.go.tpl new file mode 100644 index 0000000..10d92f5 --- /dev/null +++ b/tool/new/template/local/hello.pb.go.tpl @@ -0,0 +1,182 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v3.19.4 +// source: hello.proto + +package v1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type HelloRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HelloRequest) Reset() { + *x = HelloRequest{} + mi := &file_hello_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HelloRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloRequest) ProtoMessage() {} + +func (x *HelloRequest) ProtoReflect() protoreflect.Message { + mi := &file_hello_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead. +func (*HelloRequest) Descriptor() ([]byte, []int) { + return file_hello_proto_rawDescGZIP(), []int{0} +} + +func (x *HelloRequest) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +type HelloResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Code int64 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HelloResponse) Reset() { + *x = HelloResponse{} + mi := &file_hello_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HelloResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HelloResponse) ProtoMessage() {} + +func (x *HelloResponse) ProtoReflect() protoreflect.Message { + mi := &file_hello_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HelloResponse.ProtoReflect.Descriptor instead. +func (*HelloResponse) Descriptor() ([]byte, []int) { + return file_hello_proto_rawDescGZIP(), []int{1} +} + +func (x *HelloResponse) GetCode() int64 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *HelloResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_hello_proto protoreflect.FileDescriptor + +const file_hello_proto_rawDesc = "" + + "\n" + + "\vhello.proto\"*\n" + + "\fHelloRequest\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\"=\n" + + "\rHelloResponse\x12\x12\n" + + "\x04code\x18\x01 \x01(\x03R\x04code\x12\x18\n" + + "\amessage\x18\x02 \x01(\tR\amessage26\n" + + "\fHelloService\x12&\n" + + "\x05Hello\x12\r.HelloRequest\x1a\x0e.HelloResponseB\x06Z\x04./v1b\x06proto3" + +var ( + file_hello_proto_rawDescOnce sync.Once + file_hello_proto_rawDescData []byte +) + +func file_hello_proto_rawDescGZIP() []byte { + file_hello_proto_rawDescOnce.Do(func() { + file_hello_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_hello_proto_rawDesc), len(file_hello_proto_rawDesc))) + }) + return file_hello_proto_rawDescData +} + +var file_hello_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_hello_proto_goTypes = []any{ + (*HelloRequest)(nil), // 0: HelloRequest + (*HelloResponse)(nil), // 1: HelloResponse +} +var file_hello_proto_depIdxs = []int32{ + 0, // 0: HelloService.Hello:input_type -> HelloRequest + 1, // 1: HelloService.Hello:output_type -> HelloResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_hello_proto_init() } +func file_hello_proto_init() { + if File_hello_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_hello_proto_rawDesc), len(file_hello_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_hello_proto_goTypes, + DependencyIndexes: file_hello_proto_depIdxs, + MessageInfos: file_hello_proto_msgTypes, + }.Build() + File_hello_proto = out.File + file_hello_proto_goTypes = nil + file_hello_proto_depIdxs = nil +} diff --git a/tool/new/template/local/hello.proto.tpl b/tool/new/template/local/hello.proto.tpl new file mode 100644 index 0000000..6feb00f --- /dev/null +++ b/tool/new/template/local/hello.proto.tpl @@ -0,0 +1,16 @@ +syntax = "proto3"; + +option go_package = "./v1"; + +message HelloRequest { + string username = 1; +} + +message HelloResponse { + int64 code = 1; + string message = 2; +} + +service HelloService { + rpc Hello(HelloRequest) returns (HelloResponse); +} \ No newline at end of file diff --git a/tool/new/template/local/hello_grpc.pb.go.tpl b/tool/new/template/local/hello_grpc.pb.go.tpl new file mode 100644 index 0000000..dbbdccb --- /dev/null +++ b/tool/new/template/local/hello_grpc.pb.go.tpl @@ -0,0 +1,121 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v3.19.4 +// source: hello.proto + +package v1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + HelloService_Hello_FullMethodName = "/HelloService/Hello" +) + +// HelloServiceClient is the client API for HelloService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type HelloServiceClient interface { + Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) +} + +type helloServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewHelloServiceClient(cc grpc.ClientConnInterface) HelloServiceClient { + return &helloServiceClient{cc} +} + +func (c *helloServiceClient) Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(HelloResponse) + err := c.cc.Invoke(ctx, HelloService_Hello_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// HelloServiceServer is the server API for HelloService service. +// All implementations must embed UnimplementedHelloServiceServer +// for forward compatibility. +type HelloServiceServer interface { + Hello(context.Context, *HelloRequest) (*HelloResponse, error) + mustEmbedUnimplementedHelloServiceServer() +} + +// UnimplementedHelloServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedHelloServiceServer struct{} + +func (UnimplementedHelloServiceServer) Hello(context.Context, *HelloRequest) (*HelloResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Hello not implemented") +} +func (UnimplementedHelloServiceServer) mustEmbedUnimplementedHelloServiceServer() {} +func (UnimplementedHelloServiceServer) testEmbeddedByValue() {} + +// UnsafeHelloServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to HelloServiceServer will +// result in compilation errors. +type UnsafeHelloServiceServer interface { + mustEmbedUnimplementedHelloServiceServer() +} + +func RegisterHelloServiceServer(s grpc.ServiceRegistrar, srv HelloServiceServer) { + // If the following call pancis, it indicates UnimplementedHelloServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&HelloService_ServiceDesc, srv) +} + +func _HelloService_Hello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HelloServiceServer).Hello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HelloService_Hello_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HelloServiceServer).Hello(ctx, req.(*HelloRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// HelloService_ServiceDesc is the grpc.ServiceDesc for HelloService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var HelloService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "HelloService", + HandlerType: (*HelloServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Hello", + Handler: _HelloService_Hello_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "hello.proto", +} diff --git a/tool/new/template/repository/Usermodel.go.tpl b/tool/new/template/repository/Usermodel.go.tpl new file mode 100644 index 0000000..14df834 --- /dev/null +++ b/tool/new/template/repository/Usermodel.go.tpl @@ -0,0 +1,33 @@ +package repository + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/sql" +) + +var _ UserModels = (*ExtraUserExec)(nil) + +type UserModels interface { + UserModel + // 可以在这里添加额外的方法接口 +} + +type ExtraUserExec struct { + *UserExec +} + +func NewUserModels(DBdsn string, Cache *CacheStruct) (UserModels, error) { + db, err := sql.ConnectDB(DBdsn, User{}) + if err != nil { + return nil, err + } + cache := sql.ConnectCache(Cache.RedisAddr, Cache.RedisPassword, Cache.Number, Cache.TtlForCache, Cache.TtlForSet) + + instance := NewUserModel(db, cache, Cache.Log) + + return &ExtraUserExec{ + instance, + }, nil +} + +// 可以在这里添加额外的方法实现 +// func (e *ExtraUserExec) ... diff --git a/tool/new/template/repository/Usermodel_gen.go.tpl b/tool/new/template/repository/Usermodel_gen.go.tpl new file mode 100644 index 0000000..5c22be5 --- /dev/null +++ b/tool/new/template/repository/Usermodel_gen.go.tpl @@ -0,0 +1,218 @@ +// Code generated by muxi curd. DO NOT EDIT. + +package repository + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/sql" + "golang.org/x/sync/singleflight" + "gorm.io/gorm" +) + +const ( + cacheUserUsernamePrefix = "cache:User:Username:" + cacheUserIdPrefix = "cache:User:Id:" +) + +var group singleflight.Group + +type UserModel interface { + Create(ctx context.Context, data *User) error + FindOne(ctx context.Context, id int64) (*User, error) + FindByUsername(ctx context.Context, Username string) (*[]User, error) + Update(ctx context.Context, data *User) error + Delete(ctx context.Context, id int64) error +} + +type UserExec struct { + exec *sql.Execute + cacheExec *sql.CacheExecute + logger logger.Logger +} + +func NewUserModel(db *gorm.DB, cache *sql.CacheExecute, logger logger.Logger) *UserExec { + exec := sql.NewExecute(User{}, db) + return &UserExec{ + exec: exec, + cacheExec: cache, + logger: logger, + } +} + +// 序列化 +func UnMarshalJSON(s string, model *User) error { + return json.Unmarshal([]byte(s), model) +} + +func UnMarshalString(s string, model *[]int64) error { + return json.Unmarshal([]byte(s), model) +} + +func (u *UserExec) Create(ctx context.Context, data *User) error { + err := u.exec.Create(ctx, data) + if err != nil { + return err + } + go u.DelCache(ctx, data) + return nil +} + +func (u *UserExec) FindOne(ctx context.Context, Id int64) (*User, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, Id) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + datacache := u.Get(ctx, cachestr) + if datacache != nil { + return datacache, nil + } + var data User + u.exec.AddWhere("Id = ?", Id) + err := u.exec.Find(ctx, &data) + if err != nil { + return nil, err + } + if data.Id == 0 { + return nil, DBNotFound + } + go u.Set(cachestr, &data) + return &data, nil + }) + if result == nil { + return nil, err + } + return result.(*User), err +} + +func (u *UserExec) FindByUsername(ctx context.Context, Username string) (*[]User, error) { + cachestr := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, Username) + result, err, _ := group.Do(cachestr, func() (interface{}, error) { + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + datascache := u.GetMany(ctx, cacheval) + if datascache != nil { + return datascache, nil + } + var datas []User + u.exec.AddWhere("Username = ?", Username) + err = u.exec.Find(ctx, &datas) + if err != nil { + return nil, err + } + if len(datas) == 0 { + return nil, DBNotFound + } + go u.SetMany(cachestr, &datas) + return &datas, nil + }) + if result == nil { + return nil, err + } + return result.(*[]User), err +} + +func (u *UserExec) Update(ctx context.Context, data *User) error { + u.exec.AddWhere("id = ?", data.Id) + err := u.exec.Update(ctx, data) + if err != nil { + return err + } + go u.DelCache(ctx, data) + return nil +} + +func (u *UserExec) Delete(ctx context.Context, id int64) error { + var data User + d, err := u.FindOne(ctx, id) + if err != nil { + return err + } + data = *d + err = u.exec.Delete(ctx, &data) + if err != nil { + return err + } + go u.DelCache(ctx, &data) + return nil +} + +// cache +func (u *UserExec) DelCache(ctx context.Context, model *User) { + err := u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserIdPrefix, model.Id), ctx) + if err != nil { + u.logger.Error("主键缓存删除失败", logger.Int64("Id", model.Id),logger.Error(err)) + } + err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserUsernamePrefix, model.Username), ctx) + if err != nil { + u.logger.Warn("非主键缓存删除失败", logger.String("Username", model.Username),logger.Error(err)) + } +} + +func (u *UserExec) Get(ctx context.Context, cachestr string) *User { + var data User + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + if err == nil { + err := UnMarshalJSON(cacheval, &data) + if err != nil { + u.logger.Warn("Json 序列化出错", logger.Error(err)) + return nil + } + return &data + } + if !errors.Is(err, CacheNotFound) { + u.logger.Warn("主键缓存获取失败", logger.Error(err)) + return nil + } + return nil +} + +func (u *UserExec) GetMany(ctx context.Context, cachestr string) *[]User { + var datas []User + cacheval, err := u.cacheExec.GetCache(cachestr, ctx) + if err == nil { + var key []int64 + err := UnMarshalString(cacheval, &key) + if err != nil { + u.logger.Warn("Json 序列化出错", logger.Error(err)) + return nil + } + for _, c := range key { + data, err := u.FindOne(ctx, c) + if err != nil { + return nil + } + datas = append(datas, *data) + } + return &datas + } + if !errors.Is(err, CacheNotFound) { + u.logger.Warn("非主键缓存获取失败", logger.Error(err)) + return nil + } + return nil +} + +func (u *UserExec) Set(cachestr string, data *User) { + ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) + err := u.cacheExec.SetCache(cachestr, ctx, data) + if err != nil { + u.logger.Warn("主键缓存设置失败", logger.Error(err)) + } + cancel() +} + +func (u *UserExec) SetMany(cachestr string, data *[]User) { + ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) + var key []int64 + for _, v := range *data { + key = append(key, v.Id) + cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, v.Id) + u.Set(cachestr, &v) + } + err := u.cacheExec.SetCache(cachestr, ctx, &key) + if err != nil { + u.logger.Warn("非主键缓存设置失败", logger.Error(err)) + } + cancel() +} \ No newline at end of file diff --git a/tool/new/template/repository/model.go.tpl b/tool/new/template/repository/model.go.tpl new file mode 100644 index 0000000..c304bb2 --- /dev/null +++ b/tool/new/template/repository/model.go.tpl @@ -0,0 +1,6 @@ +package repository + +type User struct { + Id int64 `gorm:"primaryKey;autoIncrement"` + Username string `gorm:"size:50;unique;"` +} diff --git a/tool/new/template/repository/provider.go.tpl b/tool/new/template/repository/provider.go.tpl new file mode 100644 index 0000000..ce370e9 --- /dev/null +++ b/tool/new/template/repository/provider.go.tpl @@ -0,0 +1,9 @@ +package repository + +import ( + "github.com/google/wire" +) + +var ProviderSet = wire.NewSet( + NewUserModels, +) diff --git a/tool/new/template/repository/var.go.tpl b/tool/new/template/repository/var.go.tpl new file mode 100644 index 0000000..71ae962 --- /dev/null +++ b/tool/new/template/repository/var.go.tpl @@ -0,0 +1,20 @@ +package repository + +import ( + "github.com/muxi-Infra/muxi-micro/pkg/logger" + "github.com/muxi-Infra/muxi-micro/pkg/sql" + "time" +) + +type CacheStruct struct { + RedisAddr string + RedisPassword string + Number int + TtlForCache time.Duration + TtlForSet time.Duration + Log logger.Logger +} + +const CacheNotFound = sql.CacheNotFound + +var DBNotFound = sql.DBNotFound diff --git a/tool/new/template/server/provider.go.tpl b/tool/new/template/server/provider.go.tpl new file mode 100644 index 0000000..9e465dc --- /dev/null +++ b/tool/new/template/server/provider.go.tpl @@ -0,0 +1,7 @@ +package server + +import "github.com/google/wire" + +var ProviderSet = wire.NewSet( + NewGRPCServer, +) diff --git a/tool/new/template/server/register.go.tpl b/tool/new/template/server/register.go.tpl new file mode 100644 index 0000000..31d75a4 --- /dev/null +++ b/tool/new/template/server/register.go.tpl @@ -0,0 +1,17 @@ +package server + +import ( + pb "helloworld/api/local/v1" + "helloworld/internal/infrastructure" + "helloworld/internal/service" + "google.golang.org/grpc" +) + +func NewGRPCServer(helloService *service.HelloService, g *infrastructure.Grpc) *grpc.Server { + opts := []grpc.ServerOption{ + grpc.UnaryInterceptor(g.ServerInterceptor()), + } + s := grpc.NewServer(opts...) + pb.RegisterHelloServiceServer(s, helloService) + return s +} diff --git a/tool/new/template/service/hello.go.tpl b/tool/new/template/service/hello.go.tpl new file mode 100644 index 0000000..c730f5d --- /dev/null +++ b/tool/new/template/service/hello.go.tpl @@ -0,0 +1,25 @@ +package service + +import ( + "context" + pb "helloworld/api/local/v1" + "helloworld/internal/repository" +) + +type HelloService struct { + pb.UnimplementedHelloServiceServer + helloRepo repository.UserModels +} + +func NewHelloService(helloRepo repository.UserModels) *HelloService { + return &HelloService{ + helloRepo: helloRepo, + } +} + +func (s *HelloService) Hello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) { + return &pb.HelloResponse{ + Message: "Hello " + req.Username, + Code: 200, + }, nil +} diff --git a/tool/new/template/service/provider.go.tpl b/tool/new/template/service/provider.go.tpl new file mode 100644 index 0000000..7186784 --- /dev/null +++ b/tool/new/template/service/provider.go.tpl @@ -0,0 +1,7 @@ +package service + +import "github.com/google/wire" + +var ProviderSet = wire.NewSet( + NewHelloService, +) \ No newline at end of file diff --git a/tool/new/template/wire/wire.go.tpl b/tool/new/template/wire/wire.go.tpl new file mode 100644 index 0000000..dea8409 --- /dev/null +++ b/tool/new/template/wire/wire.go.tpl @@ -0,0 +1,23 @@ +//go:build wireinject + +package wire + +import ( + "github.com/google/wire" + "helloworld/internal/infrastructure" + "helloworld/internal/repository" + "helloworld/internal/server" + "helloworld/internal/service" + "google.golang.org/grpc" +) + +func WireApp() (*grpc.Server, func(), error) { + panic(wire.Build( + infrastructure.ProvideGrpcInstance, + infrastructure.ProvideDB, + infrastructure.ProvideCache, + repository.ProviderSet, + service.ProviderSet, + server.ProviderSet, + )) +} diff --git a/tool/new/template/wire/wire_gen.go.tpl b/tool/new/template/wire/wire_gen.go.tpl new file mode 100644 index 0000000..a6204ac --- /dev/null +++ b/tool/new/template/wire/wire_gen.go.tpl @@ -0,0 +1,40 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate go run -mod=mod github.com/google/wire/cmd/wire +//go:build !wireinject +// +build !wireinject + +package wire + +import ( + "helloworld/internal/infrastructure" + "helloworld/internal/repository" + "helloworld/internal/server" + "helloworld/internal/service" + "google.golang.org/grpc" +) + +// Injectors from wire.go: + +func WireApp() (*grpc.Server, func(), error) { + string2, err := infrastructure.ProvideDB() + if err != nil { + return nil, nil, err + } + infrastructureGrpc, err := infrastructure.ProvideGrpcInstance() + if err != nil { + return nil, nil, err + } + cacheStruct, err := infrastructure.ProvideCache(infrastructureGrpc) + if err != nil { + return nil, nil, err + } + userModels, err := repository.NewUserModels(string2, cacheStruct) + if err != nil { + return nil, nil, err + } + helloService := service.NewHelloService(userModels) + grpcServer := server.NewGRPCServer(helloService, infrastructureGrpc) + return grpcServer, func() { + }, nil +} From 2d00e3cc7e394434280c5345842893743221e210 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Mon, 22 Sep 2025 10:48:36 +0800 Subject: [PATCH 18/19] =?UTF-8?q?:=20=E6=96=B0=E5=A2=9E=E7=94=9F?= =?UTF-8?q?=E6=88=90test=E9=83=A8=E5=88=86;:=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=BA=86new=E7=9A=84=5Ftest=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 + go.sum | 5 + tool/cobra.go | 2 + tool/curd/parse/{parsestruct.go => parse.go} | 0 tool/helloworld/api/local/v1/hello.pb.go | 182 --------------- tool/helloworld/api/local/v1/hello.proto | 16 -- tool/helloworld/api/local/v1/hello_grpc.pb.go | 121 ---------- tool/helloworld/cmd/main.go | 26 --- tool/helloworld/configs/config.yaml | 15 -- tool/helloworld/configs/load.go | 55 ----- tool/helloworld/explain.md | 17 -- tool/helloworld/go.mod | 13 -- tool/helloworld/go.sum | 14 -- .../internal/infrastructure/interceptor.go | 18 -- .../internal/infrastructure/provider.go | 84 ------- .../internal/repository/Usermodel.go | 33 --- .../internal/repository/Usermodel_gen.go | 218 ------------------ tool/helloworld/internal/repository/model.go | 6 - .../internal/repository/provider.go | 9 - tool/helloworld/internal/repository/var.go | 20 -- tool/helloworld/internal/server/provider.go | 7 - tool/helloworld/internal/server/register.go | 17 -- tool/helloworld/internal/service/hello.go | 25 -- tool/helloworld/internal/service/provider.go | 7 - tool/helloworld/internal/wire/wire.go | 23 -- tool/helloworld/internal/wire/wire_gen.go | 40 ---- tool/new/create/create.go | 8 +- tool/new/new_test.go | 7 +- tool/new/template/Dockerfile.tpl | 44 ++++ tool/tests/create/create.go | 88 +++++++ tool/tests/example/dao.go | 24 ++ tool/tests/example/mock_dao.go | 70 ++++++ tool/tests/example/service.go | 35 +++ tool/tests/parse/parse.go | 134 +++++++++++ tool/tests/template/header.tpl | 8 + tool/tests/template/injectTest.tpl | 30 +++ tool/tests/template/test.tpl | 25 ++ tool/tests/test.go | 46 ++++ tool/tests/test_test.go | 29 +++ 39 files changed, 553 insertions(+), 970 deletions(-) rename tool/curd/parse/{parsestruct.go => parse.go} (100%) delete mode 100644 tool/helloworld/api/local/v1/hello.pb.go delete mode 100644 tool/helloworld/api/local/v1/hello.proto delete mode 100644 tool/helloworld/api/local/v1/hello_grpc.pb.go delete mode 100644 tool/helloworld/cmd/main.go delete mode 100644 tool/helloworld/configs/config.yaml delete mode 100644 tool/helloworld/configs/load.go delete mode 100644 tool/helloworld/explain.md delete mode 100644 tool/helloworld/go.mod delete mode 100644 tool/helloworld/go.sum delete mode 100644 tool/helloworld/internal/infrastructure/interceptor.go delete mode 100644 tool/helloworld/internal/infrastructure/provider.go delete mode 100644 tool/helloworld/internal/repository/Usermodel.go delete mode 100644 tool/helloworld/internal/repository/Usermodel_gen.go delete mode 100644 tool/helloworld/internal/repository/model.go delete mode 100644 tool/helloworld/internal/repository/provider.go delete mode 100644 tool/helloworld/internal/repository/var.go delete mode 100644 tool/helloworld/internal/server/provider.go delete mode 100644 tool/helloworld/internal/server/register.go delete mode 100644 tool/helloworld/internal/service/hello.go delete mode 100644 tool/helloworld/internal/service/provider.go delete mode 100644 tool/helloworld/internal/wire/wire.go delete mode 100644 tool/helloworld/internal/wire/wire_gen.go create mode 100644 tool/new/template/Dockerfile.tpl create mode 100644 tool/tests/create/create.go create mode 100644 tool/tests/example/dao.go create mode 100644 tool/tests/example/mock_dao.go create mode 100644 tool/tests/example/service.go create mode 100644 tool/tests/parse/parse.go create mode 100644 tool/tests/template/header.tpl create mode 100644 tool/tests/template/injectTest.tpl create mode 100644 tool/tests/template/test.tpl create mode 100644 tool/tests/test.go create mode 100644 tool/tests/test_test.go diff --git a/go.mod b/go.mod index b2e239c..4e0842e 100644 --- a/go.mod +++ b/go.mod @@ -67,6 +67,7 @@ require ( github.com/eapache/go-resiliency v1.7.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect + github.com/elliotchance/c2go v0.26.11 // indirect github.com/gabriel-vasile/mimetype v1.4.10 // indirect github.com/gin-contrib/sse v1.1.0 // indirect github.com/gin-contrib/timeout v1.0.2 // indirect @@ -122,6 +123,7 @@ require ( github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/ugorji/go/codec v1.3.0 // indirect go.uber.org/atomic v1.9.0 // indirect + go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/arch v0.20.0 // indirect golang.org/x/crypto v0.41.0 // indirect diff --git a/go.sum b/go.sum index 2443824..6cbdc44 100644 --- a/go.sum +++ b/go.sum @@ -121,6 +121,8 @@ github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4A github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/elliotchance/c2go v0.26.11 h1:9w+3mpFoJskiDoN0RQ1C1c3fFlDBdiQ+DoWsxMCuiwQ= +github.com/elliotchance/c2go v0.26.11/go.mod h1:+YFuwnXljn61f5sFHSZ66eH9KTjzzSU6QG1sZdg1l7s= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -435,6 +437,8 @@ go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= @@ -586,6 +590,7 @@ golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181109182537-4e34152f1676/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= diff --git a/tool/cobra.go b/tool/cobra.go index aec7ceb..21fc195 100644 --- a/tool/cobra.go +++ b/tool/cobra.go @@ -3,6 +3,7 @@ package main import ( "github.com/muxi-Infra/muxi-micro/tool/curd" "github.com/muxi-Infra/muxi-micro/tool/new" + "github.com/muxi-Infra/muxi-micro/tool/tests" "github.com/spf13/cobra" ) @@ -14,6 +15,7 @@ func main() { muxiCmd.AddCommand(curd.InitCurdCobra()) muxiCmd.AddCommand(new.InitNewCobra()) + muxiCmd.AddCommand(tests.InitTestCobra()) _ = muxiCmd.Execute() } diff --git a/tool/curd/parse/parsestruct.go b/tool/curd/parse/parse.go similarity index 100% rename from tool/curd/parse/parsestruct.go rename to tool/curd/parse/parse.go diff --git a/tool/helloworld/api/local/v1/hello.pb.go b/tool/helloworld/api/local/v1/hello.pb.go deleted file mode 100644 index 10d92f5..0000000 --- a/tool/helloworld/api/local/v1/hello.pb.go +++ /dev/null @@ -1,182 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.36.6 -// protoc v3.19.4 -// source: hello.proto - -package v1 - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" - unsafe "unsafe" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type HelloRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *HelloRequest) Reset() { - *x = HelloRequest{} - mi := &file_hello_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *HelloRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HelloRequest) ProtoMessage() {} - -func (x *HelloRequest) ProtoReflect() protoreflect.Message { - mi := &file_hello_proto_msgTypes[0] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead. -func (*HelloRequest) Descriptor() ([]byte, []int) { - return file_hello_proto_rawDescGZIP(), []int{0} -} - -func (x *HelloRequest) GetUsername() string { - if x != nil { - return x.Username - } - return "" -} - -type HelloResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Code int64 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` - Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *HelloResponse) Reset() { - *x = HelloResponse{} - mi := &file_hello_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *HelloResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HelloResponse) ProtoMessage() {} - -func (x *HelloResponse) ProtoReflect() protoreflect.Message { - mi := &file_hello_proto_msgTypes[1] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HelloResponse.ProtoReflect.Descriptor instead. -func (*HelloResponse) Descriptor() ([]byte, []int) { - return file_hello_proto_rawDescGZIP(), []int{1} -} - -func (x *HelloResponse) GetCode() int64 { - if x != nil { - return x.Code - } - return 0 -} - -func (x *HelloResponse) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - -var File_hello_proto protoreflect.FileDescriptor - -const file_hello_proto_rawDesc = "" + - "\n" + - "\vhello.proto\"*\n" + - "\fHelloRequest\x12\x1a\n" + - "\busername\x18\x01 \x01(\tR\busername\"=\n" + - "\rHelloResponse\x12\x12\n" + - "\x04code\x18\x01 \x01(\x03R\x04code\x12\x18\n" + - "\amessage\x18\x02 \x01(\tR\amessage26\n" + - "\fHelloService\x12&\n" + - "\x05Hello\x12\r.HelloRequest\x1a\x0e.HelloResponseB\x06Z\x04./v1b\x06proto3" - -var ( - file_hello_proto_rawDescOnce sync.Once - file_hello_proto_rawDescData []byte -) - -func file_hello_proto_rawDescGZIP() []byte { - file_hello_proto_rawDescOnce.Do(func() { - file_hello_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_hello_proto_rawDesc), len(file_hello_proto_rawDesc))) - }) - return file_hello_proto_rawDescData -} - -var file_hello_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_hello_proto_goTypes = []any{ - (*HelloRequest)(nil), // 0: HelloRequest - (*HelloResponse)(nil), // 1: HelloResponse -} -var file_hello_proto_depIdxs = []int32{ - 0, // 0: HelloService.Hello:input_type -> HelloRequest - 1, // 1: HelloService.Hello:output_type -> HelloResponse - 1, // [1:2] is the sub-list for method output_type - 0, // [0:1] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_hello_proto_init() } -func file_hello_proto_init() { - if File_hello_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_hello_proto_rawDesc), len(file_hello_proto_rawDesc)), - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_hello_proto_goTypes, - DependencyIndexes: file_hello_proto_depIdxs, - MessageInfos: file_hello_proto_msgTypes, - }.Build() - File_hello_proto = out.File - file_hello_proto_goTypes = nil - file_hello_proto_depIdxs = nil -} diff --git a/tool/helloworld/api/local/v1/hello.proto b/tool/helloworld/api/local/v1/hello.proto deleted file mode 100644 index 6feb00f..0000000 --- a/tool/helloworld/api/local/v1/hello.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "proto3"; - -option go_package = "./v1"; - -message HelloRequest { - string username = 1; -} - -message HelloResponse { - int64 code = 1; - string message = 2; -} - -service HelloService { - rpc Hello(HelloRequest) returns (HelloResponse); -} \ No newline at end of file diff --git a/tool/helloworld/api/local/v1/hello_grpc.pb.go b/tool/helloworld/api/local/v1/hello_grpc.pb.go deleted file mode 100644 index dbbdccb..0000000 --- a/tool/helloworld/api/local/v1/hello_grpc.pb.go +++ /dev/null @@ -1,121 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.5.1 -// - protoc v3.19.4 -// source: hello.proto - -package v1 - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.64.0 or later. -const _ = grpc.SupportPackageIsVersion9 - -const ( - HelloService_Hello_FullMethodName = "/HelloService/Hello" -) - -// HelloServiceClient is the client API for HelloService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type HelloServiceClient interface { - Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) -} - -type helloServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewHelloServiceClient(cc grpc.ClientConnInterface) HelloServiceClient { - return &helloServiceClient{cc} -} - -func (c *helloServiceClient) Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(HelloResponse) - err := c.cc.Invoke(ctx, HelloService_Hello_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -// HelloServiceServer is the server API for HelloService service. -// All implementations must embed UnimplementedHelloServiceServer -// for forward compatibility. -type HelloServiceServer interface { - Hello(context.Context, *HelloRequest) (*HelloResponse, error) - mustEmbedUnimplementedHelloServiceServer() -} - -// UnimplementedHelloServiceServer must be embedded to have -// forward compatible implementations. -// -// NOTE: this should be embedded by value instead of pointer to avoid a nil -// pointer dereference when methods are called. -type UnimplementedHelloServiceServer struct{} - -func (UnimplementedHelloServiceServer) Hello(context.Context, *HelloRequest) (*HelloResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Hello not implemented") -} -func (UnimplementedHelloServiceServer) mustEmbedUnimplementedHelloServiceServer() {} -func (UnimplementedHelloServiceServer) testEmbeddedByValue() {} - -// UnsafeHelloServiceServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to HelloServiceServer will -// result in compilation errors. -type UnsafeHelloServiceServer interface { - mustEmbedUnimplementedHelloServiceServer() -} - -func RegisterHelloServiceServer(s grpc.ServiceRegistrar, srv HelloServiceServer) { - // If the following call pancis, it indicates UnimplementedHelloServiceServer was - // embedded by pointer and is nil. This will cause panics if an - // unimplemented method is ever invoked, so we test this at initialization - // time to prevent it from happening at runtime later due to I/O. - if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { - t.testEmbeddedByValue() - } - s.RegisterService(&HelloService_ServiceDesc, srv) -} - -func _HelloService_Hello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(HelloRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(HelloServiceServer).Hello(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: HelloService_Hello_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(HelloServiceServer).Hello(ctx, req.(*HelloRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// HelloService_ServiceDesc is the grpc.ServiceDesc for HelloService service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var HelloService_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "HelloService", - HandlerType: (*HelloServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Hello", - Handler: _HelloService_Hello_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "hello.proto", -} diff --git a/tool/helloworld/cmd/main.go b/tool/helloworld/cmd/main.go deleted file mode 100644 index 874abaf..0000000 --- a/tool/helloworld/cmd/main.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "helloworld/internal/infrastructure" - "helloworld/internal/wire" - "log" - "net" -) - -func main() { - grpcInstance, err := infrastructure.ProvideGrpcInstance() - if err != nil { - log.Fatal(err) - } - s, _, err := wire.WireApp() - if err != nil { - log.Fatal(err) - } - lis, err := net.Listen(grpcInstance.Net, grpcInstance.Addr) - if err != nil { - log.Fatal(err) - } - if err := s.Serve(lis); err != nil { - log.Fatal(err) - } -} diff --git a/tool/helloworld/configs/config.yaml b/tool/helloworld/configs/config.yaml deleted file mode 100644 index 89e4b63..0000000 --- a/tool/helloworld/configs/config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -server: - grpc: - addr: 0.0.0.0:50051 - timeout: 5s -data: - mysql: - dsn: root:root@tcp(localhost:3306)/circle2?parseTime=true&charset=utf8mb4&loc=Local - redis: - addr: localhost:6379 - password: 123456 - num: 0 - read: 0.2s - write: 0.2s -log: - dir: ./logs diff --git a/tool/helloworld/configs/load.go b/tool/helloworld/configs/load.go deleted file mode 100644 index e72e7d2..0000000 --- a/tool/helloworld/configs/load.go +++ /dev/null @@ -1,55 +0,0 @@ -package configs - -import ( - "github.com/muxi-Infra/muxi-micro/pkg/config" - "sync" - "time" -) - -var ( - configOnce sync.Once - configInstance *Config - configErr error -) - -type Config struct { - Server struct { - Grpc struct { - Addr string `yaml:"addr"` - Network string `yaml:"network"` - Timeout time.Duration `yaml:"timeout"` - } `yaml:"grpc"` - } `yaml:"server"` - Data struct { - MySQL struct { - Dsn string `yaml:"dsn"` - } `yaml:"mysql"` - Redis struct { - Addr string `yaml:"addr"` - Password string `yaml:"password"` - Num int `yaml:"num"` - Read time.Duration `yaml:"read"` - Write time.Duration `yaml:"write"` - } `yaml:"redis"` - } `yaml:"data"` - Log struct { - Dir string `yaml:"dir"` - } `yaml:"log"` -} - -func LoadConfig() (*Config, error) { - configOnce.Do(func() { - cfg, err := config.NewLocalConfig(&Config{}, "../../configs/config.yaml") - if err != nil { - configErr = err - return - } - err = cfg.LoadData() - if err != nil { - configErr = err - return - } - configInstance = cfg.GetData().(*Config) - }) - return configInstance, configErr -} diff --git a/tool/helloworld/explain.md b/tool/helloworld/explain.md deleted file mode 100644 index 82e1329..0000000 --- a/tool/helloworld/explain.md +++ /dev/null @@ -1,17 +0,0 @@ -# 项目结构 -```gas -helloworld/ -├── api/ -│ ├── local/ 存放本地proto -│ │ └── v1/ -│ └── third_party/ 存放第三方proto -├── cmd/ 主函数所在地 -├── configs/ 读取配置 -└── internal/ - ├── infrastructure/ 基础设施层(提供DB,redisDB,logger等,中间件等) - ├── repository/ 仓储层(配合自动curd使用) - ├── server/ grpc注册 - ├── service/ 服务层(具体业务逻辑) - └── wire/ wire依赖注入 -``` - diff --git a/tool/helloworld/go.mod b/tool/helloworld/go.mod deleted file mode 100644 index decd624..0000000 --- a/tool/helloworld/go.mod +++ /dev/null @@ -1,13 +0,0 @@ -module helloworld - -go 1.24.5 - -require ( - github.com/google/wire v0.7.0 // indirect - golang.org/x/net v0.41.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/grpc v1.75.1 // indirect - google.golang.org/protobuf v1.36.6 // indirect -) diff --git a/tool/helloworld/go.sum b/tool/helloworld/go.sum deleted file mode 100644 index 9464001..0000000 --- a/tool/helloworld/go.sum +++ /dev/null @@ -1,14 +0,0 @@ -github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= -github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI= -google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= diff --git a/tool/helloworld/internal/infrastructure/interceptor.go b/tool/helloworld/internal/infrastructure/interceptor.go deleted file mode 100644 index e6afa61..0000000 --- a/tool/helloworld/internal/infrastructure/interceptor.go +++ /dev/null @@ -1,18 +0,0 @@ -package infrastructure - -import ( - "context" - "github.com/muxi-Infra/muxi-micro/pkg/logger" - "google.golang.org/grpc" -) - -func (g *Grpc) ServerInterceptor() grpc.UnaryServerInterceptor { - return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { - resp, err = handler(ctx, req) - if err != nil { - str := g.Addr + " 发生错误" - g.logger.Error(str, logger.Error(err)) - } - return resp, err - } -} diff --git a/tool/helloworld/internal/infrastructure/provider.go b/tool/helloworld/internal/infrastructure/provider.go deleted file mode 100644 index 04c58d0..0000000 --- a/tool/helloworld/internal/infrastructure/provider.go +++ /dev/null @@ -1,84 +0,0 @@ -package infrastructure - -import ( - "errors" - "github.com/google/wire" - "helloworld/configs" - "helloworld/internal/repository" - "github.com/muxi-Infra/muxi-micro/pkg/logger" - "github.com/muxi-Infra/muxi-micro/pkg/logger/zapx" - "sync" - "time" -) - -var ProviderSet = wire.NewSet( - ProvideGrpcInstance, - ProvideDB, - ProvideCache, -) - -type Grpc struct { - logger logger.Logger - Addr string - Timeout time.Duration - Net string -} - -var ( - Err error - Once sync.Once - instance *Grpc -) - -var MissingAddrErr = errors.New("you should add a address(like 0.0.0.0:50051) on the configs") - -func ProvideGrpcInstance() (*Grpc, error) { - Once.Do(func() { - cfg, err := configs.LoadConfig() - if err != nil { - Err = err - return - } - if cfg.Server.Grpc.Addr == "" { - Err = MissingAddrErr - return - } - if cfg.Server.Grpc.Timeout == 0 { - cfg.Server.Grpc.Timeout = 10 * time.Second - } - if cfg.Server.Grpc.Network == "" { - cfg.Server.Grpc.Network = "tcp" - } - instance = &Grpc{ - logger: zapx.NewDefaultZapLogger(cfg.Log.Dir, logger.EnvTest), - Addr: cfg.Server.Grpc.Addr, - Timeout: cfg.Server.Grpc.Timeout, - Net: cfg.Server.Grpc.Network, - } - }) - return instance, Err -} - -func ProvideDB() (string, error) { - cfg, err := configs.LoadConfig() - if err != nil { - return "", err - } - return cfg.Data.MySQL.Dsn, nil -} - -func ProvideCache(g *Grpc) (*repository.CacheStruct, error) { - cfg, err := configs.LoadConfig() - if err != nil { - return nil, err - } - data := cfg.Data.Redis - return &repository.CacheStruct{ - RedisAddr: data.Addr, - RedisPassword: data.Password, - Number: data.Num, - TtlForCache: data.Read, - TtlForSet: data.Write, - Log: g.logger, - }, nil -} diff --git a/tool/helloworld/internal/repository/Usermodel.go b/tool/helloworld/internal/repository/Usermodel.go deleted file mode 100644 index 14df834..0000000 --- a/tool/helloworld/internal/repository/Usermodel.go +++ /dev/null @@ -1,33 +0,0 @@ -package repository - -import ( - "github.com/muxi-Infra/muxi-micro/pkg/sql" -) - -var _ UserModels = (*ExtraUserExec)(nil) - -type UserModels interface { - UserModel - // 可以在这里添加额外的方法接口 -} - -type ExtraUserExec struct { - *UserExec -} - -func NewUserModels(DBdsn string, Cache *CacheStruct) (UserModels, error) { - db, err := sql.ConnectDB(DBdsn, User{}) - if err != nil { - return nil, err - } - cache := sql.ConnectCache(Cache.RedisAddr, Cache.RedisPassword, Cache.Number, Cache.TtlForCache, Cache.TtlForSet) - - instance := NewUserModel(db, cache, Cache.Log) - - return &ExtraUserExec{ - instance, - }, nil -} - -// 可以在这里添加额外的方法实现 -// func (e *ExtraUserExec) ... diff --git a/tool/helloworld/internal/repository/Usermodel_gen.go b/tool/helloworld/internal/repository/Usermodel_gen.go deleted file mode 100644 index 5c22be5..0000000 --- a/tool/helloworld/internal/repository/Usermodel_gen.go +++ /dev/null @@ -1,218 +0,0 @@ -// Code generated by muxi curd. DO NOT EDIT. - -package repository - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "github.com/muxi-Infra/muxi-micro/pkg/logger" - "github.com/muxi-Infra/muxi-micro/pkg/sql" - "golang.org/x/sync/singleflight" - "gorm.io/gorm" -) - -const ( - cacheUserUsernamePrefix = "cache:User:Username:" - cacheUserIdPrefix = "cache:User:Id:" -) - -var group singleflight.Group - -type UserModel interface { - Create(ctx context.Context, data *User) error - FindOne(ctx context.Context, id int64) (*User, error) - FindByUsername(ctx context.Context, Username string) (*[]User, error) - Update(ctx context.Context, data *User) error - Delete(ctx context.Context, id int64) error -} - -type UserExec struct { - exec *sql.Execute - cacheExec *sql.CacheExecute - logger logger.Logger -} - -func NewUserModel(db *gorm.DB, cache *sql.CacheExecute, logger logger.Logger) *UserExec { - exec := sql.NewExecute(User{}, db) - return &UserExec{ - exec: exec, - cacheExec: cache, - logger: logger, - } -} - -// 序列化 -func UnMarshalJSON(s string, model *User) error { - return json.Unmarshal([]byte(s), model) -} - -func UnMarshalString(s string, model *[]int64) error { - return json.Unmarshal([]byte(s), model) -} - -func (u *UserExec) Create(ctx context.Context, data *User) error { - err := u.exec.Create(ctx, data) - if err != nil { - return err - } - go u.DelCache(ctx, data) - return nil -} - -func (u *UserExec) FindOne(ctx context.Context, Id int64) (*User, error) { - cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, Id) - result, err, _ := group.Do(cachestr, func() (interface{}, error) { - datacache := u.Get(ctx, cachestr) - if datacache != nil { - return datacache, nil - } - var data User - u.exec.AddWhere("Id = ?", Id) - err := u.exec.Find(ctx, &data) - if err != nil { - return nil, err - } - if data.Id == 0 { - return nil, DBNotFound - } - go u.Set(cachestr, &data) - return &data, nil - }) - if result == nil { - return nil, err - } - return result.(*User), err -} - -func (u *UserExec) FindByUsername(ctx context.Context, Username string) (*[]User, error) { - cachestr := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, Username) - result, err, _ := group.Do(cachestr, func() (interface{}, error) { - cacheval, err := u.cacheExec.GetCache(cachestr, ctx) - datascache := u.GetMany(ctx, cacheval) - if datascache != nil { - return datascache, nil - } - var datas []User - u.exec.AddWhere("Username = ?", Username) - err = u.exec.Find(ctx, &datas) - if err != nil { - return nil, err - } - if len(datas) == 0 { - return nil, DBNotFound - } - go u.SetMany(cachestr, &datas) - return &datas, nil - }) - if result == nil { - return nil, err - } - return result.(*[]User), err -} - -func (u *UserExec) Update(ctx context.Context, data *User) error { - u.exec.AddWhere("id = ?", data.Id) - err := u.exec.Update(ctx, data) - if err != nil { - return err - } - go u.DelCache(ctx, data) - return nil -} - -func (u *UserExec) Delete(ctx context.Context, id int64) error { - var data User - d, err := u.FindOne(ctx, id) - if err != nil { - return err - } - data = *d - err = u.exec.Delete(ctx, &data) - if err != nil { - return err - } - go u.DelCache(ctx, &data) - return nil -} - -// cache -func (u *UserExec) DelCache(ctx context.Context, model *User) { - err := u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserIdPrefix, model.Id), ctx) - if err != nil { - u.logger.Error("主键缓存删除失败", logger.Int64("Id", model.Id),logger.Error(err)) - } - err = u.cacheExec.DeleteCache(fmt.Sprintf("%s%v", cacheUserUsernamePrefix, model.Username), ctx) - if err != nil { - u.logger.Warn("非主键缓存删除失败", logger.String("Username", model.Username),logger.Error(err)) - } -} - -func (u *UserExec) Get(ctx context.Context, cachestr string) *User { - var data User - cacheval, err := u.cacheExec.GetCache(cachestr, ctx) - if err == nil { - err := UnMarshalJSON(cacheval, &data) - if err != nil { - u.logger.Warn("Json 序列化出错", logger.Error(err)) - return nil - } - return &data - } - if !errors.Is(err, CacheNotFound) { - u.logger.Warn("主键缓存获取失败", logger.Error(err)) - return nil - } - return nil -} - -func (u *UserExec) GetMany(ctx context.Context, cachestr string) *[]User { - var datas []User - cacheval, err := u.cacheExec.GetCache(cachestr, ctx) - if err == nil { - var key []int64 - err := UnMarshalString(cacheval, &key) - if err != nil { - u.logger.Warn("Json 序列化出错", logger.Error(err)) - return nil - } - for _, c := range key { - data, err := u.FindOne(ctx, c) - if err != nil { - return nil - } - datas = append(datas, *data) - } - return &datas - } - if !errors.Is(err, CacheNotFound) { - u.logger.Warn("非主键缓存获取失败", logger.Error(err)) - return nil - } - return nil -} - -func (u *UserExec) Set(cachestr string, data *User) { - ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) - err := u.cacheExec.SetCache(cachestr, ctx, data) - if err != nil { - u.logger.Warn("主键缓存设置失败", logger.Error(err)) - } - cancel() -} - -func (u *UserExec) SetMany(cachestr string, data *[]User) { - ctx, cancel := context.WithTimeout(context.Background(), u.cacheExec.SetTTl) - var key []int64 - for _, v := range *data { - key = append(key, v.Id) - cachestr := fmt.Sprintf("%s%v", cacheUserIdPrefix, v.Id) - u.Set(cachestr, &v) - } - err := u.cacheExec.SetCache(cachestr, ctx, &key) - if err != nil { - u.logger.Warn("非主键缓存设置失败", logger.Error(err)) - } - cancel() -} \ No newline at end of file diff --git a/tool/helloworld/internal/repository/model.go b/tool/helloworld/internal/repository/model.go deleted file mode 100644 index c304bb2..0000000 --- a/tool/helloworld/internal/repository/model.go +++ /dev/null @@ -1,6 +0,0 @@ -package repository - -type User struct { - Id int64 `gorm:"primaryKey;autoIncrement"` - Username string `gorm:"size:50;unique;"` -} diff --git a/tool/helloworld/internal/repository/provider.go b/tool/helloworld/internal/repository/provider.go deleted file mode 100644 index ce370e9..0000000 --- a/tool/helloworld/internal/repository/provider.go +++ /dev/null @@ -1,9 +0,0 @@ -package repository - -import ( - "github.com/google/wire" -) - -var ProviderSet = wire.NewSet( - NewUserModels, -) diff --git a/tool/helloworld/internal/repository/var.go b/tool/helloworld/internal/repository/var.go deleted file mode 100644 index 71ae962..0000000 --- a/tool/helloworld/internal/repository/var.go +++ /dev/null @@ -1,20 +0,0 @@ -package repository - -import ( - "github.com/muxi-Infra/muxi-micro/pkg/logger" - "github.com/muxi-Infra/muxi-micro/pkg/sql" - "time" -) - -type CacheStruct struct { - RedisAddr string - RedisPassword string - Number int - TtlForCache time.Duration - TtlForSet time.Duration - Log logger.Logger -} - -const CacheNotFound = sql.CacheNotFound - -var DBNotFound = sql.DBNotFound diff --git a/tool/helloworld/internal/server/provider.go b/tool/helloworld/internal/server/provider.go deleted file mode 100644 index 9e465dc..0000000 --- a/tool/helloworld/internal/server/provider.go +++ /dev/null @@ -1,7 +0,0 @@ -package server - -import "github.com/google/wire" - -var ProviderSet = wire.NewSet( - NewGRPCServer, -) diff --git a/tool/helloworld/internal/server/register.go b/tool/helloworld/internal/server/register.go deleted file mode 100644 index 31d75a4..0000000 --- a/tool/helloworld/internal/server/register.go +++ /dev/null @@ -1,17 +0,0 @@ -package server - -import ( - pb "helloworld/api/local/v1" - "helloworld/internal/infrastructure" - "helloworld/internal/service" - "google.golang.org/grpc" -) - -func NewGRPCServer(helloService *service.HelloService, g *infrastructure.Grpc) *grpc.Server { - opts := []grpc.ServerOption{ - grpc.UnaryInterceptor(g.ServerInterceptor()), - } - s := grpc.NewServer(opts...) - pb.RegisterHelloServiceServer(s, helloService) - return s -} diff --git a/tool/helloworld/internal/service/hello.go b/tool/helloworld/internal/service/hello.go deleted file mode 100644 index c730f5d..0000000 --- a/tool/helloworld/internal/service/hello.go +++ /dev/null @@ -1,25 +0,0 @@ -package service - -import ( - "context" - pb "helloworld/api/local/v1" - "helloworld/internal/repository" -) - -type HelloService struct { - pb.UnimplementedHelloServiceServer - helloRepo repository.UserModels -} - -func NewHelloService(helloRepo repository.UserModels) *HelloService { - return &HelloService{ - helloRepo: helloRepo, - } -} - -func (s *HelloService) Hello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) { - return &pb.HelloResponse{ - Message: "Hello " + req.Username, - Code: 200, - }, nil -} diff --git a/tool/helloworld/internal/service/provider.go b/tool/helloworld/internal/service/provider.go deleted file mode 100644 index 7186784..0000000 --- a/tool/helloworld/internal/service/provider.go +++ /dev/null @@ -1,7 +0,0 @@ -package service - -import "github.com/google/wire" - -var ProviderSet = wire.NewSet( - NewHelloService, -) \ No newline at end of file diff --git a/tool/helloworld/internal/wire/wire.go b/tool/helloworld/internal/wire/wire.go deleted file mode 100644 index dea8409..0000000 --- a/tool/helloworld/internal/wire/wire.go +++ /dev/null @@ -1,23 +0,0 @@ -//go:build wireinject - -package wire - -import ( - "github.com/google/wire" - "helloworld/internal/infrastructure" - "helloworld/internal/repository" - "helloworld/internal/server" - "helloworld/internal/service" - "google.golang.org/grpc" -) - -func WireApp() (*grpc.Server, func(), error) { - panic(wire.Build( - infrastructure.ProvideGrpcInstance, - infrastructure.ProvideDB, - infrastructure.ProvideCache, - repository.ProviderSet, - service.ProviderSet, - server.ProviderSet, - )) -} diff --git a/tool/helloworld/internal/wire/wire_gen.go b/tool/helloworld/internal/wire/wire_gen.go deleted file mode 100644 index a6204ac..0000000 --- a/tool/helloworld/internal/wire/wire_gen.go +++ /dev/null @@ -1,40 +0,0 @@ -// Code generated by Wire. DO NOT EDIT. - -//go:generate go run -mod=mod github.com/google/wire/cmd/wire -//go:build !wireinject -// +build !wireinject - -package wire - -import ( - "helloworld/internal/infrastructure" - "helloworld/internal/repository" - "helloworld/internal/server" - "helloworld/internal/service" - "google.golang.org/grpc" -) - -// Injectors from wire.go: - -func WireApp() (*grpc.Server, func(), error) { - string2, err := infrastructure.ProvideDB() - if err != nil { - return nil, nil, err - } - infrastructureGrpc, err := infrastructure.ProvideGrpcInstance() - if err != nil { - return nil, nil, err - } - cacheStruct, err := infrastructure.ProvideCache(infrastructureGrpc) - if err != nil { - return nil, nil, err - } - userModels, err := repository.NewUserModels(string2, cacheStruct) - if err != nil { - return nil, nil, err - } - helloService := service.NewHelloService(userModels) - grpcServer := server.NewGRPCServer(helloService, infrastructureGrpc) - return grpcServer, func() { - }, nil -} diff --git a/tool/new/create/create.go b/tool/new/create/create.go index e82697b..18fa01e 100644 --- a/tool/new/create/create.go +++ b/tool/new/create/create.go @@ -1,12 +1,15 @@ package create import ( + "errors" "fmt" "io/ioutil" "os" "path/filepath" ) +var DirNotEsxitErr = errors.New("can not find dir") + func CreateDocument(rootDir string) error { dirs := []string{ filepath.Join(rootDir, "helloworld", "api", "local", "v1"), @@ -158,7 +161,7 @@ func CreateWire(rootDir string) error { } func CreateExplain(rootDir string) error { - paths := []string{"explain.md", "go.mod", "go.sum"} + paths := []string{"explain.md", "go.mod", "go.sum", "Dockerfile"} for _, p := range paths { templatePath := filepath.Join("new", "template", p+".tpl") templateContent, err := ioutil.ReadFile(templatePath) @@ -174,6 +177,9 @@ func CreateExplain(rootDir string) error { } func CreateAll(rootDir string) error { + if _, err := os.Stat(rootDir); err != nil { + return DirNotEsxitErr + } if err := CreateDocument(rootDir); err != nil { return err } diff --git a/tool/new/new_test.go b/tool/new/new_test.go index 3008da4..46818de 100644 --- a/tool/new/new_test.go +++ b/tool/new/new_test.go @@ -1,9 +1,10 @@ package new import ( - "github.com/stretchr/testify/assert" "strings" "testing" + + "github.com/stretchr/testify/assert" ) func TestNew(t *testing.T) { @@ -12,9 +13,9 @@ func TestNew(t *testing.T) { var output strings.Builder newCmd.SetOutput(&output) newCmd.SetArgs([]string{ - "--dir", "test", + "--dir", "dir not exist", }) err := newCmd.Execute() - assert.ErrorContains(t, err, "The system cannot find the path specified") + assert.ErrorContains(t, err, "can not find dir") }) } diff --git a/tool/new/template/Dockerfile.tpl b/tool/new/template/Dockerfile.tpl new file mode 100644 index 0000000..906e997 --- /dev/null +++ b/tool/new/template/Dockerfile.tpl @@ -0,0 +1,44 @@ +# 第一阶段:构建 Go 应用 +FROM golang:alpine AS builder + +# 设置 Go 代理为七牛云的代理 +ENV GOPROXY=https://goproxy.cn,direct + +# 安装需要的依赖 +RUN apk update && apk add --no-cache git + +# 切换到 app 目录,构建二进制文件 +WORKDIR /helloworld-backend + +# 复制代码 +COPY . . + +RUN go mod tidy && go build -o helloworld + +# 确认文件存在 +RUN ls -lh /helloworld-backend + +# 第二阶段:复制编译结果到最终镜像 +FROM alpine + +# 安装 tzdata 来设置时区 +RUN apk add --no-cache tzdata + +# 设置时区为 Asia/Shanghai +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ + echo "Asia/Shanghai" > /etc/timezone + +# 设置工作目录为 +WORKDIR /helloworld-backend + +# 从 builder 复制编译好的二进制文件 +COPY --from=builder /helloworld-backend/helloworld . + +# 复制配置文件到最终镜像(尽量不要这么做) +# COPY --from=builder /app/config /app/config + +# 开放端口(根据需要设置) +EXPOSE 50051 + +# 启动用户服务 +CMD ["./helloworld"] diff --git a/tool/tests/create/create.go b/tool/tests/create/create.go new file mode 100644 index 0000000..33b2f04 --- /dev/null +++ b/tool/tests/create/create.go @@ -0,0 +1,88 @@ +package create + +import ( + "os" + "path/filepath" + "strings" + "text/template" + + "github.com/muxi-Infra/muxi-micro/tool/tests/parse" +) + +type ParseStruct struct { + PackageName string + Func *[]parse.FuncStruct +} + +func CreateFunc(filePath string, funcStructs *[]parse.FuncStruct, packName string) error { + if len(*funcStructs) == 0 { + return nil + } + var tmplPath []string + tmplPath = []string{ + filepath.Join("tests", "template", "header.tpl"), + filepath.Join("tests", "template", "test.tpl"), + } + + t, err := template.New("example").ParseFiles(tmplPath...) + if err != nil { + return err + } + + dir := filepath.Dir(filePath) + outputPath := filepath.Join(dir, GetFileName(filePath)+"_test.go") + file, err := os.Create(outputPath) + if err != nil { + return err + } + defer file.Close() + + data := &ParseStruct{ + PackageName: packName, + Func: funcStructs, + } + if err := t.ExecuteTemplate(file, "header", data); err != nil { + return err + } + + return nil +} + +func CreateRece(filePath string, receStructs *[]parse.FuncStruct, packName string) error { + if len(*receStructs) == 0 { + return nil + } + var tmplPath []string + tmplPath = []string{ + filepath.Join("tests", "template", "header.tpl"), + filepath.Join("tests", "template", "injectTest.tpl"), + } + + t, err := template.New("example").ParseFiles(tmplPath...) + if err != nil { + return err + } + + dir := filepath.Dir(filePath) + outputPath := filepath.Join(dir, GetFileName(filePath)+"_test2.go") + file, err := os.Create(outputPath) + if err != nil { + return err + } + defer file.Close() + + data := &ParseStruct{ + PackageName: packName, + Func: receStructs, + } + if err := t.ExecuteTemplate(file, "header", data); err != nil { + return err + } + + return nil +} + +func GetFileName(filePath string) string { + filename := filepath.Base(filePath) + return strings.TrimSuffix(filename, ".go") +} diff --git a/tool/tests/example/dao.go b/tool/tests/example/dao.go new file mode 100644 index 0000000..8b39897 --- /dev/null +++ b/tool/tests/example/dao.go @@ -0,0 +1,24 @@ +package example + +import "context" + +//go:generate mockgen -destination=mock_dao.go -package=example . UserDAO + +type UserDAO interface { + GetUserByID(ctx context.Context, id int64) (*User, error) + CreateUser(ctx context.Context, user *User) error +} + +type User struct { + ID int64 + Name string + Age int +} + +func (u *User) GetUserByID(ctx context.Context, id int64) (*User, error) { + return u, nil +} + +func (u *User) CreateUser(ctx context.Context, user *User) (bool, error) { + return true, nil +} diff --git a/tool/tests/example/mock_dao.go b/tool/tests/example/mock_dao.go new file mode 100644 index 0000000..376bc80 --- /dev/null +++ b/tool/tests/example/mock_dao.go @@ -0,0 +1,70 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/muxi-Infra/muxi-micro/tool/tests/example (interfaces: UserDAO) +// +// Generated by this command: +// +// mockgen -destination=mock_dao.go -package=example . UserDAO +// + +// Package example is a generated GoMock package. +package example + +import ( + context "context" + reflect "reflect" + + gomock "go.uber.org/mock/gomock" +) + +// MockUserDAO is a mock of UserDAO interface. +type MockUserDAO struct { + ctrl *gomock.Controller + recorder *MockUserDAOMockRecorder + isgomock struct{} +} + +// MockUserDAOMockRecorder is the mock recorder for MockUserDAO. +type MockUserDAOMockRecorder struct { + mock *MockUserDAO +} + +// NewMockUserDAO creates a new mock instance. +func NewMockUserDAO(ctrl *gomock.Controller) *MockUserDAO { + mock := &MockUserDAO{ctrl: ctrl} + mock.recorder = &MockUserDAOMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockUserDAO) EXPECT() *MockUserDAOMockRecorder { + return m.recorder +} + +// CreateUser mocks base method. +func (m *MockUserDAO) CreateUser(ctx context.Context, user *User) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateUser", ctx, user) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateUser indicates an expected call of CreateUser. +func (mr *MockUserDAOMockRecorder) CreateUser(ctx, user any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUser", reflect.TypeOf((*MockUserDAO)(nil).CreateUser), ctx, user) +} + +// GetUserByID mocks base method. +func (m *MockUserDAO) GetUserByID(ctx context.Context, id int64) (*User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserByID", ctx, id) + ret0, _ := ret[0].(*User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserByID indicates an expected call of GetUserByID. +func (mr *MockUserDAOMockRecorder) GetUserByID(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByID", reflect.TypeOf((*MockUserDAO)(nil).GetUserByID), ctx, id) +} diff --git a/tool/tests/example/service.go b/tool/tests/example/service.go new file mode 100644 index 0000000..a630f11 --- /dev/null +++ b/tool/tests/example/service.go @@ -0,0 +1,35 @@ +package example + +import ( + "context" + "errors" +) + +type UserService struct { + userDAO UserDAO +} + +func NewUserService(userDAO UserDAO) *UserService { + return &UserService{userDAO: userDAO} +} + +func (s *UserService) GetUser(ctx context.Context, id int64) (*User, error) { + if id <= 0 { + return nil, errors.New("invalid user id") + } + return s.userDAO.GetUserByID(ctx, id) +} + +func (s *UserService) CreateUser(ctx context.Context, name string, age int) error { + if name == "" { + return errors.New("name cannot be empty") + } + if age <= 0 { + return errors.New("age must be positive") + } + + return s.userDAO.CreateUser(ctx, &User{ + Name: name, + Age: age, + }) +} diff --git a/tool/tests/parse/parse.go b/tool/tests/parse/parse.go new file mode 100644 index 0000000..be92a84 --- /dev/null +++ b/tool/tests/parse/parse.go @@ -0,0 +1,134 @@ +package parse + +import ( + "errors" + "fmt" + "go/ast" + "go/parser" + "go/token" +) + +var TooManyErr = errors.New("to many error are not recommended") + +type Value struct { + Param string + ParamType string +} + +type FuncStruct struct { + Receive string + FuncName string + Params []Value + Returns []Value +} + +func ParsePackage(filePath string) (string, error) { + fset := token.NewFileSet() + node, err := parser.ParseFile(fset, filePath, nil, parser.PackageClauseOnly) + if err != nil { + return "", err + } + return node.Name.Name, nil +} + +func ParseFunc(filePath string) (*[]FuncStruct, *[]FuncStruct, error) { + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, filePath, nil, 0) + if err != nil { + return nil, nil, err + } + + var Funcs, Reces []FuncStruct + for _, decl := range f.Decls { + if fn, ok := decl.(*ast.FuncDecl); ok { + var Func FuncStruct + var flag bool + if fn.Recv != nil { + Func.Receive = exprToString(fn.Recv.List[0].Type) + } + Func.FuncName = fn.Name.Name + if fn.Type.Params != nil { + for _, field := range fn.Type.Params.List { + typeStr := exprToString(field.Type) + for _, name := range field.Names { + Func.Params = append(Func.Params, Value{ + Param: identToString(name), + ParamType: typeStr, + }) + } + } + } + if fn.Type.Results != nil { + for _, field := range fn.Type.Results.List { + typeStr := exprToString(field.Type) + var str string + if typeStr == "error" { + if flag == true { + return nil, nil, TooManyErr + } + str = "err" + flag = true + } else { + str = "expected" + fmt.Sprintf("%v", len(Func.Returns)+1) + } + Func.Returns = append(Func.Returns, Value{ + Param: str, + ParamType: typeStr, + }) + } + } + if Func.Receive == "" { + Funcs = append(Funcs, Func) + } else { + Reces = append(Reces, Func) + } + } + } + return &Funcs, &Reces, nil +} + +func identToString(ident *ast.Ident) string { + if ident == nil { + return "" + } + return ident.Name +} + +func exprToString(expr ast.Expr) string { + switch v := expr.(type) { + // 基础类型 + case *ast.Ident: + return v.Name + // 包(如: context.Context) + case *ast.SelectorExpr: + return exprToString(v.X) + "." + v.Sel.Name + // 指针 + case *ast.StarExpr: + return "*" + exprToString(v.X) + // 切片或数组 + case *ast.ArrayType: + if v.Len == nil { + return "[]" + exprToString(v.Elt) + } + return "[" + exprToString(v.Len) + "]" + exprToString(v.Elt) + // 哈希表 + case *ast.MapType: + return "map[" + exprToString(v.Key) + "]" + exprToString(v.Value) + // 可变参数(如: ...int) + case *ast.Ellipsis: + return "..." + exprToString(v.Elt) + // 管道 + case *ast.ChanType: + switch v.Dir { + case ast.SEND: + return "chan<- " + exprToString(v.Value) + case ast.RECV: + return "<-chan " + exprToString(v.Value) + default: + return "chan " + exprToString(v.Value) + } + // 否则 interface 或 struct,func 等未命名的返回值返回 interface + default: + return "interface{}" + } +} diff --git a/tool/tests/template/header.tpl b/tool/tests/template/header.tpl new file mode 100644 index 0000000..777bbcd --- /dev/null +++ b/tool/tests/template/header.tpl @@ -0,0 +1,8 @@ +{{- define "header" -}} +package {{.PackageName}} + +import ( + "testing" +) +{{template "test" $}} +{{- end -}} \ No newline at end of file diff --git a/tool/tests/template/injectTest.tpl b/tool/tests/template/injectTest.tpl new file mode 100644 index 0000000..f69388c --- /dev/null +++ b/tool/tests/template/injectTest.tpl @@ -0,0 +1,30 @@ +{{- define "test" -}} +{{range $func := .Func}} +func Test{{$func.FuncName}}(t *testing.T) { + var MockInjection = func() {{$func.Receive}} { + // TODO: 添加注入的逻辑,推荐 "go.uber.org/mock/gomock" + } + object := MockInjection() + + type testCase struct { + description string + {{range $input := $func.Params -}} + {{$input.Param}} {{$input.ParamType}} + {{end -}} + {{range $return := $func.Returns -}} + {{$return.Param}} {{$return.ParamType}} + {{end}} + } + tests := []testCase{ + // TODO: 添加测试用例 + + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + // TODO: 添加测试逻辑 + }) + } +} +{{end -}} +{{- end -}} diff --git a/tool/tests/template/test.tpl b/tool/tests/template/test.tpl new file mode 100644 index 0000000..b1309e2 --- /dev/null +++ b/tool/tests/template/test.tpl @@ -0,0 +1,25 @@ +{{- define "test" -}} +{{range $func := .Func}} +func Test{{$func.FuncName}}(t *testing.T) { + type testCase struct { + description string + {{range $input := $func.Params -}} + {{$input.Param}} {{$input.ParamType}} + {{end -}} + {{range $return := $func.Returns -}} + {{$return.Param}} {{$return.ParamType}} + {{end}} + } + tests := []testCase{ + // TODO: 添加测试用例 + + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + // TODO: 添加测试逻辑 + }) + } +} +{{end -}} +{{- end -}} \ No newline at end of file diff --git a/tool/tests/test.go b/tool/tests/test.go new file mode 100644 index 0000000..74b87c1 --- /dev/null +++ b/tool/tests/test.go @@ -0,0 +1,46 @@ +package tests + +import ( + "github.com/muxi-Infra/muxi-micro/tool/tests/create" + "github.com/muxi-Infra/muxi-micro/tool/tests/parse" + "github.com/spf13/cobra" +) + +func InitTestCobra() *cobra.Command { + // test 子命令 + var testCmd = &cobra.Command{ + Use: "test", + Short: "test 生成测试文件", + RunE: func(cmd *cobra.Command, args []string) error { + filePath, _ := cmd.Flags().GetString("file") + function, _ := cmd.Flags().GetBool("func") + receiver, _ := cmd.Flags().GetBool("receive") + funcStruct, RecesStruct, err := parse.ParseFunc(filePath) + if err != nil { + return err + } + packName, err := parse.ParsePackage(filePath) + if err != nil { + return err + } + if function { + if err := create.CreateFunc(filePath, funcStruct, packName); err != nil { + return err + } + } + if receiver { + if err := create.CreateRece(filePath, RecesStruct, packName); err != nil { + return err + } + } + return nil + }, + } + + testCmd.Flags().String("file", "", "想要生成测试文件的路径") + testCmd.Flags().Bool("func", false, "生成函数的测试") + testCmd.Flags().Bool("receive", false, "生成方法的测试") + testCmd.MarkFlagRequired("file") + + return testCmd +} diff --git a/tool/tests/test_test.go b/tool/tests/test_test.go new file mode 100644 index 0000000..256633a --- /dev/null +++ b/tool/tests/test_test.go @@ -0,0 +1,29 @@ +package tests + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTest(t *testing.T) { + t.Run("file not write", func(t *testing.T) { + testCmd := InitTestCobra() + var output strings.Builder + testCmd.SetOutput(&output) + err := testCmd.Execute() + assert.ErrorContains(t, err, "\"file\" not set") + }) + + t.Run("file not exist", func(t *testing.T) { + testCmd := InitTestCobra() + var output strings.Builder + testCmd.SetOutput(&output) + testCmd.SetArgs([]string{ + "--file", "nonexist.go", + }) + err := testCmd.Execute() + assert.ErrorContains(t, err, "The system cannot find the file specified.") + }) +} From 8d7e27c2d2a18740eaff364f3660e0b6eb6fe6c3 Mon Sep 17 00:00:00 2001 From: luohuixi <2388287244@qq.com> Date: Mon, 22 Sep 2025 10:55:20 +0800 Subject: [PATCH 19/19] =?UTF-8?q?:=20=E6=96=B0=E5=A2=9E=E7=94=9F?= =?UTF-8?q?=E6=88=90test=E9=83=A8=E5=88=86;:=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=BA=86new=E7=9A=84=5Ftest=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tool/tests/test_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tool/tests/test_test.go b/tool/tests/test_test.go index 256633a..9ac61f9 100644 --- a/tool/tests/test_test.go +++ b/tool/tests/test_test.go @@ -24,6 +24,11 @@ func TestTest(t *testing.T) { "--file", "nonexist.go", }) err := testCmd.Execute() - assert.ErrorContains(t, err, "The system cannot find the file specified.") + assert.Error(t, err) + assert.True(t, + strings.Contains(err.Error(), "The system cannot find the file specified") || + strings.Contains(err.Error(), "no such file or directory"), + "错误消息不匹配", + ) }) }