diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 8215ab6..a1315b5 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -6,9 +6,14 @@ on: - develop paths: - "bff/**" - - "product/**" - - "admin/**" - - "user/**" + - "services/product/**" + - "services/admin/**" + - "services/user/**" + - "services/ad/**" + - "rpc/product/**" + - "rpc/admin/**" + - "rpc/user/**" + - "rpc/ad/**" - "pkg/**" - ".gitea/workflows/ci.yml" workflow_dispatch: @@ -21,6 +26,7 @@ jobs: product: ${{ steps.filter.outputs.product }} admin: ${{ steps.filter.outputs.admin }} user: ${{ steps.filter.outputs.user }} + ad: ${{ steps.filter.outputs.ad }} steps: - name: Checkout uses: https://git.ailuowan.com/deploy/checkout@v4 @@ -34,12 +40,14 @@ jobs: product=false admin=false user=false + ad=false if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then bff=true product=true admin=true user=true + ad=true else before="${{ github.event.before }}" if [ -z "$before" ] || [ "$before" = "0000000000000000000000000000000000000000" ]; then @@ -51,17 +59,19 @@ jobs: echo "changed files:" echo "$changed" - echo "$changed" | grep -qE '^(bff|pkg)/|^\.gitea/workflows/ci\.yml$' && bff=true || true - echo "$changed" | grep -qE '^(product|pkg)/|^\.gitea/workflows/ci\.yml$' && product=true || true - echo "$changed" | grep -qE '^(admin|pkg)/|^\.gitea/workflows/ci\.yml$' && admin=true || true - echo "$changed" | grep -qE '^(user|pkg)/|^\.gitea/workflows/ci\.yml$' && user=true || true + echo "$changed" | grep -qE '^(bff|pkg|rpc)/|^\.gitea/workflows/ci\.yml$' && bff=true || true + echo "$changed" | grep -qE '^(services/product|rpc/product|pkg)/|^\.gitea/workflows/ci\.yml$' && product=true || true + echo "$changed" | grep -qE '^(services/admin|rpc/admin|pkg)/|^\.gitea/workflows/ci\.yml$' && admin=true || true + echo "$changed" | grep -qE '^(services/user|rpc/user|pkg)/|^\.gitea/workflows/ci\.yml$' && user=true || true + echo "$changed" | grep -qE '^(services/ad|rpc/ad|pkg)/|^\.gitea/workflows/ci\.yml$' && ad=true || true fi echo "bff=$bff" >> "$GITHUB_OUTPUT" echo "product=$product" >> "$GITHUB_OUTPUT" echo "admin=$admin" >> "$GITHUB_OUTPUT" echo "user=$user" >> "$GITHUB_OUTPUT" - echo "bff=$bff product=$product admin=$admin user=$user" + echo "ad=$ad" >> "$GITHUB_OUTPUT" + echo "bff=$bff product=$product admin=$admin user=$user ad=$ad" docker-bff: needs: changes @@ -162,3 +172,28 @@ jobs: - name: Docker push run: | docker push ${{ vars.REGISTRY }}/$NAME:latest + + docker-ad: + needs: changes + if: needs.changes.outputs.ad == 'true' + runs-on: runner + env: + NAME: lone/ad + steps: + - name: Checkout + uses: https://git.ailuowan.com/deploy/checkout@v4 + + - name: Login Registry + run: | + echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ vars.REGISTRY }} -u "${{ vars.REGISTRY_USERNAME }}" --password-stdin + + - name: Docker build + run: | + docker buildx build --load \ + -f services/ad/Dockerfile \ + -t ${{ vars.REGISTRY }}/$NAME:latest \ + . + + - name: Docker push + run: | + docker push ${{ vars.REGISTRY }}/$NAME:latest diff --git a/README-NEW.md b/README-NEW.md deleted file mode 100644 index 17eadf3..0000000 --- a/README-NEW.md +++ /dev/null @@ -1,330 +0,0 @@ -## 常用命令 - -### 命令 goctl 生成/更新脚手架 - -```bash -cd lone-services/ -rpc/scripts/gen-rpc.sh 服务名 如 product -``` - -**什么时候跑:** - -- 增删改 **字段**(BFF gateway 编解码需要) -- 增删 **RPC** -- 改 **google.api.http** 路由 - - - -## 如何加一个新服务 - -以加 `order` 为例(对标现有 `product`)。 - -### 0. 安装 goctl - -```bash -go install github.com/zeromicro/go-zero/tools/goctl@latest -goctl --version -go install google.golang.org/protobuf/cmd/protoc-gen-go@latest -go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest -``` - -### 1. 创建 RPC 服务(goctl) - -在仓库根目录执行: - -```bash -cd services -goctl rpc new order -cd order -``` - -### 2. 将 proto 移到 `proto/` 目录 - -`goctl rpc new` 默认把 proto 放在服务根目录(如 `order/order.proto`)。统一挪到 `../rpc/order/order.proto`: - -```bash -mkdir ../rpc/proto -mv order.proto proto/ -修改 option go_package="./order"; 为 option go_package="lone-services/rpc/order"; - -``` - -### 3. 删除order目录 - -### 4. Zero 兼容 Nacos 等配置 - -编辑 `order/internal/config/config.go`: - -```go -package config - -type Config struct { - Nacos NacosConf -} - -type NacosConf struct { - Hosts []string - NamespaceId string `json:",optional"` - Group string `json:",optional"` - RegisterIP string `json:",optional"` - ConfigID string `json:",optional"` -} - -``` - -### 5. 配置服务名与监听端口 - -编辑 `order/etc/order.yaml`: - -```yaml -Nacos: - Hosts: - - host.docker.internal:8848 - NamespaceId: test - Group: LONE_SERVICES - RegisterIP: order - ConfigID: develop-order -``` - - -### 6. 服务注册 - -编辑 `order/order.go`: - -增加初始化 - -```go - -func main() { -flag.Parse() -var c config.Config -conf.MustLoad(*configFile, &c) - -// Nacos配置拉取初始化 -nacosParam := utils.NacosConfig{ -Hosts: c.Nacos.Hosts, -NamespaceId: c.Nacos.NamespaceId, -Group: c.Nacos.Group, -ConfigID: c.Nacos.ConfigID, -} -utils.InitConfig(nacosParam) - -// 日志配置 -logConf := logx.LogConf{ -ServiceName: utils.GetConfigString("log.serviceName"), -Mode: utils.GetConfigString("log.mode"), -Encoding: utils.GetConfigString("log.encoding"), -Level: utils.GetConfigString("log.level"), -Path: utils.GetConfigString("log.path"), -KeepDays: utils.GetConfigInt("log.keepDays"), -MaxSize: utils.GetConfigInt("log.maxSize"), -MaxBackups: utils.GetConfigInt("log.maxBackups"), -Compress: utils.GetConfigBool("log.compress"), -} -logx.SetUp(logConf) -logx.AddWriter(logx.NewWriter(os.Stdout)) - -listenOn := utils.GetConfigString("base.listenOn") -mode := utils.GetConfigString("base.mode") -serviceName := utils.GetConfigString("base.name") - -// 初始化服务发现 -if err := discovery.Init(discovery.Config{ -Hosts: c.Nacos.Hosts, -NamespaceId: c.Nacos.NamespaceId, -Group: c.Nacos.Group, -}); err != nil { -logx.Errorf("nacos init: %v", err) -os.Exit(1) -} - -port, err := listenPort(listenOn) -if err != nil { -logx.Errorf("parse ListenOn: %v", err) -os.Exit(1) -} - -// 注册服务 -if err := discovery.Register(discovery.Instance{ -ServiceName: serviceName, -IP: c.Nacos.RegisterIP, -Port: port, -Group: c.Nacos.Group, -}); err != nil { -logx.Errorf("nacos register: %v", err) -os.Exit(1) -} -logx.Infof("服务注册成功: %s:%d", c.Nacos.RegisterIP, port) - -defer func() { -if err := discovery.Deregister(); err != nil { -logx.Errorf("nacos deregister: %v", err) -} -}() - -// 初始化MySQL -db, err := mysql.New(mysql.Config{ -Host: utils.GetConfigString("mysql.host"), -Port: utils.GetConfigInt("mysql.port"), -User: utils.GetConfigString("mysql.user"), -Password: utils.GetConfigString("mysql.password"), -Database: utils.GetConfigString("mysql.database"), -Charset: utils.GetConfigString("mysql.charset"), -Prefix: utils.GetConfigString("mysql.prefix"), -ReadHost: utils.GetConfigString("mysql_read.host"), -ReadPort: utils.GetConfigInt("mysql_read.port"), -ReadUser: utils.GetConfigString("mysql_read.user"), -ReadPassword: utils.GetConfigString("mysql_read.password"), -ReadDatabase: utils.GetConfigString("mysql_read.database"), -}) -if err != nil { -logx.Errorf("mysql init: %v", err) -os.Exit(1) -} - -// 初始化Redis -if err := redis.Init(redis.Config{ -Host: utils.GetConfigString("redis.host"), -Port: utils.GetConfigInt("redis.port"), -Password: utils.GetConfigString("redis.password"), -DB: utils.GetConfigInt("redis.db"), -}); err != nil { -logx.Errorf("redis init: %v", err) -os.Exit(1) -} - -//日志队列初始化 -if err := logRedis.Init(logRedis.LogRedisConfig{ -Host: utils.GetConfigString("log-redis.host"), -Port: utils.GetConfigInt("log-redis.port"), -Password: utils.GetConfigString("log-redis.password"), -DB: utils.GetConfigInt("log-redis.db"), -}); err != nil { -logx.Errorf("log redis init: %v", err) -os.Exit(1) -} - -debug := utils.GetConfigBool("mysql.debug") -modelbase.Init(db, modelbase.Config{Prefix: utils.GetConfigString("mysql.prefix"), Debug: debug}) - -// 初始化服务信息 -rpcConf := zrpc.RpcServerConf{ -ListenOn: listenOn, -} -rpcConf.Mode = mode -ctx := svc.NewServiceContext(c, db) - -s := zrpc.MustNewServer(rpcConf, func(grpcServer *grpc.Server) { -order.RegisterOrderServer(grpcServer, server.NewOrderServer(ctx)) -if mode == service.DevMode || mode == service.TestMode { -reflection.Register(grpcServer) -} -}) -defer s.Stop() - -s.AddUnaryInterceptors(validate.UnaryServerInterceptor(validate.MustNew())) - -logx.Infof("Starting rpc server at %s...", listenOn) -s.Start() -} - -// listenPort 拆分端口 -func listenPort(listenOn string) (uint64, error) { -_, portStr, err := net.SplitHostPort(listenOn) -if err != nil { -return utils.NumberZero, err -} -return strconv.ParseUint(portStr, utils.NumberTen, utils.NumberSixtyFourth) -} - - -``` - -执行 tidy - -```bash -go mod tidy -``` - -编辑 `internal/svc/servicecontext.go`: - -```go -package svc - -import ( - "lone-services/pkg/utils" - "lone-services/services/order/internal/config" - - "gorm.io/gorm" -) - -type ServiceContext struct { - Config config.Config - DB *gorm.DB - Prefix string -} - -func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { - return &ServiceContext{ - Config: c, - DB: db, - Prefix: utils.GetConfigString("mysql.prefix"), - } -} - - -``` - -### 7. 接入 Docker Compose - -在 `deploy/docker-compose.dev.override.yml` 增加服务: - -```yaml - order: - image: golang:1.26.5 - volumes: - - ..:/src - - go-mod-cache:/go/pkg/mod - - go-build-cache:/root/.cache/go-build - working_dir: /src/services/order - command: go run . -f etc/order.yaml - ports: - - "10200:10200" - environment: - NACOS_SERVER_ADDR: rnacos:8848 - depends_on: - - rnacos -``` - -### 9. 在 BFF 配 Upstream(HTTP 路由写在 proto) - -编辑 `bff/etc/bff.yaml`,在 **Upstreams** 增加一段(不必写 Mappings,gateway 会从 ProtoSet 里的 http option 注册路由): - -```yaml - - Name: order - Grpc: - Target: order-service # 必须等于 order.yaml 的 Name - Timeout: 5000 - ProtoSets: - - etc/order.pb -``` - -在对应 RPC 上声明 `google.api.http`(需 `import "google/api/annotations.proto";`): - -```protobuf -rpc Ping(Request) returns (Response) { - option (google.api.http) = { - post: "/admin/v3/order/ping" - body: "*" - }; -} -``` - -### 编写业务须知 - -只改业务逻辑(`internal/logic/`)不必跑 goctl。 -改 `proto/order.proto`(新增/改名 RPC、改字段、改 http option 等)后,按文末「三条命令何时用」处理; - -若 HTTP 路径有变,改 proto 里的 `google.api.http` 后重新跑命令 ② 生成 ProtoSet。 - ---- \ No newline at end of file diff --git a/README.md b/README.md index 98e7505..37dd270 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,9 @@ ## 常用命令 -### 命令 ①:goctl 生成/更新脚手架 - ```bash -goctl -I. -I../pkg/third_party rpc protoc proto/order.proto --go_out=. --go-grpc_out=. --zrpc_out=. +rpc/scripts/gen-rpc.sh order ``` -### 命令 ②:生成服务端 pb / grpc - -```bash -goctl rpc protoc proto/order.proto --proto_path=. --proto_path=../pkg/third_party --go_out=. --go-grpc_out=. --zrpc_out=. -``` - -**什么时候跑:** - -- 只改 **校验规则**(必填/长度/范围等)→ **只跑这条** -- 增删改字段、增删 RPC → 也要跑(服务端描述符要更新) - -### 命令 ③:生成 BFF ProtoSet - -```bash -protoc -I. -I../pkg/third_party --descriptor_set_out=../bff/etc/order.pb --include_imports proto/order.proto -``` - -**什么时候跑:** - -- 增删改 **字段**(BFF gateway 编解码需要) -- 增删 **RPC** -- 改 **google.api.http** 路由 - ## 如何加一个新服务 以加 `order` 为例(对标现有 `product`)。 @@ -47,20 +22,36 @@ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 在仓库根目录执行: ```bash +cd services goctl rpc new order -cd order +cd ../rpc +mkdir order + ``` -### 2. 将 proto 移到 `proto/` 目录 +### 2. 将 proto 移到 `rpc/` 目录 -`goctl rpc new` 默认把 proto 放在服务根目录(如 `order/order.proto`)。统一挪到 `proto/`: +`goctl rpc new` 默认把 proto 放在服务根目录(如 `order/order.proto`)。统一挪到 `rpc/`: ```bash -mkdir proto -mv order.proto proto/ +cd ../services/order +mv order.proto ../../rpc/order/ ``` -### 3. Zero 兼容 Nacos 等配置 +编辑 `rpc/order/order.proto`,把 `go_package` 改成本仓库模块路径: + +```protobuf +option go_package = "lone-services/rpc/order"; +``` + +### 3. 生成pb 文件 + +windows 用 git 的 bash 跑 +```bash +D:\Git\bin\bash.exe rpc/scripts/gen-rpc.sh order +``` + +### 4. Zero 兼容 Nacos 等配置 编辑 `order/internal/config/config.go`: @@ -80,47 +71,22 @@ type NacosConf struct { } ``` -### 4. 配置服务名与监听端口 +### 5. 配置服务名与监听端口 编辑 `order/etc/order.yaml`: ```yaml Nacos: Hosts: - - host.docker.internal:8848 + - rnacos:8848 NamespaceId: test Group: LONE_SERVICES - RegisterIP: admin - ConfigID: develop-admin + RegisterIP: order + ConfigID: order ``` -### 5. 构建 mod - -编辑 `order/go.mod` 增加本地包 pkg.local - -```go -go 1.26 - -replace pkg.local => ../pkg -``` - - - ### 6. 服务注册 -编辑 `order/order.go`: - -增加 import - -```go -"pkg.local/discovery" -"pkg.local/modelbase" -"pkg.local/mysql" -"pkg.local/redis" -"pkg.local/validate" -"pkg.local/utils" -``` - 增加初始化 ```go @@ -251,12 +217,6 @@ func listenPort(listenOn string) (uint64, error) { ``` -执行 tidy - -```bash -go mod tidy -``` - 编辑 `internal/svc/servicecontext.go`: ```go @@ -279,7 +239,7 @@ func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { ### 7. 接入 Docker Compose -在 `deploy/docker-compose.dev.override.yml` 增加服务: +在 `deploy/docker-compose.override.yml` 增加服务: ```yaml order: @@ -288,7 +248,7 @@ func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { - ..:/src - go-mod-cache:/go/pkg/mod - go-build-cache:/root/.cache/go-build - working_dir: /src/order + working_dir: /src/services/order command: go run . -f etc/order.yaml ports: - "10200:10200" @@ -298,13 +258,7 @@ func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { - rnacos ``` -### 8. 生成 ProtoSet 给 BFF - -```bash -protoc --include_imports --proto_path=proto --descriptor_set_out=../bff/etc/order.pb order.proto -``` - -### 9. 在 BFF 配 Upstream(HTTP 路由写在 proto) +### 8. 在 BFF 配 Upstream(HTTP 路由写在 proto) 编辑 `bff/etc/bff.yaml`,在 **Upstreams** 增加一段(不必写 Mappings,gateway 会从 ProtoSet 里的 http option 注册路由): @@ -314,63 +268,9 @@ protoc --include_imports --proto_path=proto --descriptor_set_out=../bff/etc/orde Target: order-service # 必须等于 order.yaml 的 Name Timeout: 5000 ProtoSets: - - etc/order.pb + - ../rpc/order/order.pb ``` -在对应 RPC 上声明 `google.api.http`(需 `import "google/api/annotations.proto";`): - -```protobuf -rpc Ping(Request) returns (Response) { - option (google.api.http) = { - post: "/admin/v3/order/ping" - body: "*" - }; -} -``` - -### 编写业务须知 - -只改业务逻辑(`internal/logic/`)不必跑 goctl。 -改 `proto/order.proto`(新增/改名 RPC、改字段、改 http option 等)后,按文末「三条命令何时用」处理; - -若 HTTP 路径有变,改 proto 里的 `google.api.http` 后重新跑命令 ② 生成 ProtoSet。 - ---- - -### 命令 ①:生成服务端 pb / grpc - -```bash -goctl rpc protoc proto/order.proto --proto_path=. --proto_path=../pkg/third_party --go_out=. --go-grpc_out=. --zrpc_out=. -``` - -**什么时候跑:** - -- 只改 **校验规则**(必填/长度/范围等)→ **只跑这条** -- 增删改字段、增删 RPC → 也要跑(服务端描述符要更新) - -### 命令 ②:生成 BFF ProtoSet - -```bash -protoc -I. -I../pkg/third_party --descriptor_set_out=../bff/etc/order.pb --include_imports proto/order.proto -``` - -**什么时候跑:** - -- 增删改 **字段**(BFF gateway 编解码需要) -- 增删 **RPC** -- 改 **google.api.http** 路由 - -### 命令 ③:goctl 生成/更新脚手架 - -```bash -goctl -I. -I../pkg/third_party rpc protoc proto/order.proto --go_out=. --go-grpc_out=. --zrpc_out=. -``` - -**什么时候跑:** - -- **新增 RPC**:需要生成 `internal/logic`、更新 `server` / `orderclient` 等 -- 注意:可能覆盖已改过的 `order.go` 等,生成后对比合并;也可用手写 logic/server 代替 - ## Proto 常用校验规则(protovalidate) 文档:[https://protovalidate.com/schemas/standard-rules/](https://protovalidate.com/schemas/standard-rules/) diff --git a/bff/Dockerfile b/bff/Dockerfile index ba251d3..121f825 100644 --- a/bff/Dockerfile +++ b/bff/Dockerfile @@ -36,6 +36,7 @@ COPY rpc/user/*.pb \ rpc/order/*.pb \ rpc/product/*.pb \ rpc/admin/*.pb \ + rpc/ad/*.pb \ rpc/lonelog/*.pb \ ./etc/ diff --git a/rpc/ad/ad.pb b/rpc/ad/ad.pb new file mode 100644 index 0000000..9a5b311 Binary files /dev/null and b/rpc/ad/ad.pb differ diff --git a/rpc/ad/ad.proto b/rpc/ad/ad.proto new file mode 100644 index 0000000..0672e1a --- /dev/null +++ b/rpc/ad/ad.proto @@ -0,0 +1,85 @@ +syntax = "proto3"; + +package ad; +option go_package = "lone-services/rpc/ad"; +import "google/api/annotations.proto"; + +service Ad { + // 添加广告 + rpc Create(CreateReq) returns (Response) { + option (google.api.http) = { + post: "/admin/v3/ad" + body: "*" + }; + } + // 编辑广告 + rpc Edit(EditReq) returns (Response) { + option (google.api.http) = { + put: "/admin/v3/ad" + body: "*" + }; + } + // 广告列表 + rpc Items(ItemsReq) returns (Response) { + option (google.api.http) = { + get: "/admin/v3/ad" + body: "*" + }; + } + // 广告状态 + rpc Status(StatusReq) returns (Response) { + option (google.api.http) = { + put: "/admin/v3/ad/status" + body: "*" + }; + } +} + +message Response { + int32 code = 1; + string msg = 2; + string data = 3; +} + +message CreateReq { + uint32 type = 1; + string image = 2; + string content = 3; + string url = 4; +} + +message EditReq { + int64 id = 1; + uint32 type = 2; + string image = 3; + string content = 4; + string url = 5; +} + +message ItemsReq { + uint32 page = 1; + uint32 page_size = 2; +} + +message StatusReq { + int64 id = 1; + uint32 status = 2; + string reason = 3; +} + +message ItemsData { + int64 count = 1; + repeated Item items = 2; +} + +message Item { + int64 id = 1; + uint32 type = 2; + string image = 3; + string content = 4; + string reason = 5; + uint32 status = 6; + string url = 7; + string update_time = 8; + string create_time = 9; +} diff --git a/rpc/ad/pb/ad.pb.go b/rpc/ad/pb/ad.pb.go new file mode 100644 index 0000000..582b8e3 --- /dev/null +++ b/rpc/ad/pb/ad.pb.go @@ -0,0 +1,612 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v3.19.4 +// source: ad/ad.proto + +package ad + +import ( + _ "google.golang.org/genproto/googleapis/api/annotations" + 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 Response struct { + state protoimpl.MessageState `protogen:"open.v1"` + Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` + Data string `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Response) Reset() { + *x = Response{} + mi := &file_ad_ad_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Response) ProtoMessage() {} + +func (x *Response) ProtoReflect() protoreflect.Message { + mi := &file_ad_ad_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 Response.ProtoReflect.Descriptor instead. +func (*Response) Descriptor() ([]byte, []int) { + return file_ad_ad_proto_rawDescGZIP(), []int{0} +} + +func (x *Response) GetCode() int32 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *Response) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +func (x *Response) GetData() string { + if x != nil { + return x.Data + } + return "" +} + +// type: 1、商城首页banner 2、商城首页视频 3、商城首页公告 4、商城首页教程 +type CreateReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type uint32 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"` + Image string `protobuf:"bytes,2,opt,name=image,proto3" json:"image,omitempty"` + Content string `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` + Url string `protobuf:"bytes,4,opt,name=url,proto3" json:"url,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateReq) Reset() { + *x = CreateReq{} + mi := &file_ad_ad_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateReq) ProtoMessage() {} + +func (x *CreateReq) ProtoReflect() protoreflect.Message { + mi := &file_ad_ad_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 CreateReq.ProtoReflect.Descriptor instead. +func (*CreateReq) Descriptor() ([]byte, []int) { + return file_ad_ad_proto_rawDescGZIP(), []int{1} +} + +func (x *CreateReq) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *CreateReq) GetImage() string { + if x != nil { + return x.Image + } + return "" +} + +func (x *CreateReq) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *CreateReq) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +type EditReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Type uint32 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"` + Image string `protobuf:"bytes,3,opt,name=image,proto3" json:"image,omitempty"` + Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"` + Url string `protobuf:"bytes,5,opt,name=url,proto3" json:"url,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EditReq) Reset() { + *x = EditReq{} + mi := &file_ad_ad_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EditReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EditReq) ProtoMessage() {} + +func (x *EditReq) ProtoReflect() protoreflect.Message { + mi := &file_ad_ad_proto_msgTypes[2] + 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 EditReq.ProtoReflect.Descriptor instead. +func (*EditReq) Descriptor() ([]byte, []int) { + return file_ad_ad_proto_rawDescGZIP(), []int{2} +} + +func (x *EditReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *EditReq) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *EditReq) GetImage() string { + if x != nil { + return x.Image + } + return "" +} + +func (x *EditReq) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *EditReq) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +type ItemsReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Page uint32 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"` + PageSize uint32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ItemsReq) Reset() { + *x = ItemsReq{} + mi := &file_ad_ad_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ItemsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ItemsReq) ProtoMessage() {} + +func (x *ItemsReq) ProtoReflect() protoreflect.Message { + mi := &file_ad_ad_proto_msgTypes[3] + 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 ItemsReq.ProtoReflect.Descriptor instead. +func (*ItemsReq) Descriptor() ([]byte, []int) { + return file_ad_ad_proto_rawDescGZIP(), []int{3} +} + +func (x *ItemsReq) GetPage() uint32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *ItemsReq) GetPageSize() uint32 { + if x != nil { + return x.PageSize + } + return 0 +} + +// status: 1 正常, 2 禁用 +type StatusReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Status uint32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"` + Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StatusReq) Reset() { + *x = StatusReq{} + mi := &file_ad_ad_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StatusReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusReq) ProtoMessage() {} + +func (x *StatusReq) ProtoReflect() protoreflect.Message { + mi := &file_ad_ad_proto_msgTypes[4] + 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 StatusReq.ProtoReflect.Descriptor instead. +func (*StatusReq) Descriptor() ([]byte, []int) { + return file_ad_ad_proto_rawDescGZIP(), []int{4} +} + +func (x *StatusReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *StatusReq) GetStatus() uint32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *StatusReq) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +type ItemsData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Count int64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` + Items []*Item `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ItemsData) Reset() { + *x = ItemsData{} + mi := &file_ad_ad_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ItemsData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ItemsData) ProtoMessage() {} + +func (x *ItemsData) ProtoReflect() protoreflect.Message { + mi := &file_ad_ad_proto_msgTypes[5] + 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 ItemsData.ProtoReflect.Descriptor instead. +func (*ItemsData) Descriptor() ([]byte, []int) { + return file_ad_ad_proto_rawDescGZIP(), []int{5} +} + +func (x *ItemsData) GetCount() int64 { + if x != nil { + return x.Count + } + return 0 +} + +func (x *ItemsData) GetItems() []*Item { + if x != nil { + return x.Items + } + return nil +} + +type Item struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Type uint32 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"` + Image string `protobuf:"bytes,3,opt,name=image,proto3" json:"image,omitempty"` + Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"` + Reason string `protobuf:"bytes,5,opt,name=reason,proto3" json:"reason,omitempty"` + Status uint32 `protobuf:"varint,6,opt,name=status,proto3" json:"status,omitempty"` + Url string `protobuf:"bytes,7,opt,name=url,proto3" json:"url,omitempty"` + UpdateTime string `protobuf:"bytes,8,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` + CreateTime string `protobuf:"bytes,9,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Item) Reset() { + *x = Item{} + mi := &file_ad_ad_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Item) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Item) ProtoMessage() {} + +func (x *Item) ProtoReflect() protoreflect.Message { + mi := &file_ad_ad_proto_msgTypes[6] + 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 Item.ProtoReflect.Descriptor instead. +func (*Item) Descriptor() ([]byte, []int) { + return file_ad_ad_proto_rawDescGZIP(), []int{6} +} + +func (x *Item) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Item) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *Item) GetImage() string { + if x != nil { + return x.Image + } + return "" +} + +func (x *Item) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *Item) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *Item) GetStatus() uint32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *Item) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *Item) GetUpdateTime() string { + if x != nil { + return x.UpdateTime + } + return "" +} + +func (x *Item) GetCreateTime() string { + if x != nil { + return x.CreateTime + } + return "" +} + +var File_ad_ad_proto protoreflect.FileDescriptor + +const file_ad_ad_proto_rawDesc = "" + + "\n" + + "\vad/ad.proto\x12\x02ad\x1a\x1cgoogle/api/annotations.proto\"D\n" + + "\bResponse\x12\x12\n" + + "\x04code\x18\x01 \x01(\x05R\x04code\x12\x10\n" + + "\x03msg\x18\x02 \x01(\tR\x03msg\x12\x12\n" + + "\x04data\x18\x03 \x01(\tR\x04data\"a\n" + + "\tCreateReq\x12\x12\n" + + "\x04type\x18\x01 \x01(\rR\x04type\x12\x14\n" + + "\x05image\x18\x02 \x01(\tR\x05image\x12\x18\n" + + "\acontent\x18\x03 \x01(\tR\acontent\x12\x10\n" + + "\x03url\x18\x04 \x01(\tR\x03url\"o\n" + + "\aEditReq\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" + + "\x04type\x18\x02 \x01(\rR\x04type\x12\x14\n" + + "\x05image\x18\x03 \x01(\tR\x05image\x12\x18\n" + + "\acontent\x18\x04 \x01(\tR\acontent\x12\x10\n" + + "\x03url\x18\x05 \x01(\tR\x03url\";\n" + + "\bItemsReq\x12\x12\n" + + "\x04page\x18\x01 \x01(\rR\x04page\x12\x1b\n" + + "\tpage_size\x18\x02 \x01(\rR\bpageSize\"K\n" + + "\tStatusReq\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x16\n" + + "\x06status\x18\x02 \x01(\rR\x06status\x12\x16\n" + + "\x06reason\x18\x03 \x01(\tR\x06reason\"A\n" + + "\tItemsData\x12\x14\n" + + "\x05count\x18\x01 \x01(\x03R\x05count\x12\x1e\n" + + "\x05items\x18\x02 \x03(\v2\b.ad.ItemR\x05items\"\xde\x01\n" + + "\x04Item\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" + + "\x04type\x18\x02 \x01(\rR\x04type\x12\x14\n" + + "\x05image\x18\x03 \x01(\tR\x05image\x12\x18\n" + + "\acontent\x18\x04 \x01(\tR\acontent\x12\x16\n" + + "\x06reason\x18\x05 \x01(\tR\x06reason\x12\x16\n" + + "\x06status\x18\x06 \x01(\rR\x06status\x12\x10\n" + + "\x03url\x18\a \x01(\tR\x03url\x12\x1f\n" + + "\vupdate_time\x18\b \x01(\tR\n" + + "updateTime\x12\x1f\n" + + "\vcreate_time\x18\t \x01(\tR\n" + + "createTime2\x85\x02\n" + + "\x02Ad\x12>\n" + + "\x06Create\x12\r.ad.CreateReq\x1a\f.ad.Response\"\x17\x82\xd3\xe4\x93\x02\x11:\x01*\"\f/admin/v3/ad\x12:\n" + + "\x04Edit\x12\v.ad.EditReq\x1a\f.ad.Response\"\x17\x82\xd3\xe4\x93\x02\x11:\x01*\x1a\f/admin/v3/ad\x12<\n" + + "\x05Items\x12\f.ad.ItemsReq\x1a\f.ad.Response\"\x17\x82\xd3\xe4\x93\x02\x11:\x01*\x12\f/admin/v3/ad\x12E\n" + + "\x06Status\x12\r.ad.StatusReq\x1a\f.ad.Response\"\x1e\x82\xd3\xe4\x93\x02\x18:\x01*\x1a\x13/admin/v3/ad/statusB\x16Z\x14lone-services/rpc/adb\x06proto3" + +var ( + file_ad_ad_proto_rawDescOnce sync.Once + file_ad_ad_proto_rawDescData []byte +) + +func file_ad_ad_proto_rawDescGZIP() []byte { + file_ad_ad_proto_rawDescOnce.Do(func() { + file_ad_ad_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ad_ad_proto_rawDesc), len(file_ad_ad_proto_rawDesc))) + }) + return file_ad_ad_proto_rawDescData +} + +var file_ad_ad_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_ad_ad_proto_goTypes = []any{ + (*Response)(nil), // 0: ad.Response + (*CreateReq)(nil), // 1: ad.CreateReq + (*EditReq)(nil), // 2: ad.EditReq + (*ItemsReq)(nil), // 3: ad.ItemsReq + (*StatusReq)(nil), // 4: ad.StatusReq + (*ItemsData)(nil), // 5: ad.ItemsData + (*Item)(nil), // 6: ad.Item +} +var file_ad_ad_proto_depIdxs = []int32{ + 6, // 0: ad.ItemsData.items:type_name -> ad.Item + 1, // 1: ad.Ad.Create:input_type -> ad.CreateReq + 2, // 2: ad.Ad.Edit:input_type -> ad.EditReq + 3, // 3: ad.Ad.Items:input_type -> ad.ItemsReq + 4, // 4: ad.Ad.Status:input_type -> ad.StatusReq + 0, // 5: ad.Ad.Create:output_type -> ad.Response + 0, // 6: ad.Ad.Edit:output_type -> ad.Response + 0, // 7: ad.Ad.Items:output_type -> ad.Response + 0, // 8: ad.Ad.Status:output_type -> ad.Response + 5, // [5:9] is the sub-list for method output_type + 1, // [1:5] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_ad_ad_proto_init() } +func file_ad_ad_proto_init() { + if File_ad_ad_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_ad_ad_proto_rawDesc), len(file_ad_ad_proto_rawDesc)), + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_ad_ad_proto_goTypes, + DependencyIndexes: file_ad_ad_proto_depIdxs, + MessageInfos: file_ad_ad_proto_msgTypes, + }.Build() + File_ad_ad_proto = out.File + file_ad_ad_proto_goTypes = nil + file_ad_ad_proto_depIdxs = nil +} diff --git a/rpc/ad/pb/ad_grpc.pb.go b/rpc/ad/pb/ad_grpc.pb.go new file mode 100644 index 0000000..afa6510 --- /dev/null +++ b/rpc/ad/pb/ad_grpc.pb.go @@ -0,0 +1,243 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.2 +// - protoc v3.19.4 +// source: ad/ad.proto + +package ad + +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 ( + Ad_Create_FullMethodName = "/ad.Ad/Create" + Ad_Edit_FullMethodName = "/ad.Ad/Edit" + Ad_Items_FullMethodName = "/ad.Ad/Items" + Ad_Status_FullMethodName = "/ad.Ad/Status" +) + +// AdClient is the client API for Ad 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 AdClient interface { + // 添加广告 + Create(ctx context.Context, in *CreateReq, opts ...grpc.CallOption) (*Response, error) + // 编辑广告 + Edit(ctx context.Context, in *EditReq, opts ...grpc.CallOption) (*Response, error) + // 广告列表 + Items(ctx context.Context, in *ItemsReq, opts ...grpc.CallOption) (*Response, error) + // 广告状态 + Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) +} + +type adClient struct { + cc grpc.ClientConnInterface +} + +func NewAdClient(cc grpc.ClientConnInterface) AdClient { + return &adClient{cc} +} + +func (c *adClient) Create(ctx context.Context, in *CreateReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Ad_Create_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adClient) Edit(ctx context.Context, in *EditReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Ad_Edit_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adClient) Items(ctx context.Context, in *ItemsReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Ad_Items_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adClient) Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Ad_Status_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AdServer is the server API for Ad service. +// All implementations must embed UnimplementedAdServer +// for forward compatibility. +type AdServer interface { + // 添加广告 + Create(context.Context, *CreateReq) (*Response, error) + // 编辑广告 + Edit(context.Context, *EditReq) (*Response, error) + // 广告列表 + Items(context.Context, *ItemsReq) (*Response, error) + // 广告状态 + Status(context.Context, *StatusReq) (*Response, error) + mustEmbedUnimplementedAdServer() +} + +// UnimplementedAdServer 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 UnimplementedAdServer struct{} + +func (UnimplementedAdServer) Create(context.Context, *CreateReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Create not implemented") +} +func (UnimplementedAdServer) Edit(context.Context, *EditReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Edit not implemented") +} +func (UnimplementedAdServer) Items(context.Context, *ItemsReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Items not implemented") +} +func (UnimplementedAdServer) Status(context.Context, *StatusReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Status not implemented") +} +func (UnimplementedAdServer) mustEmbedUnimplementedAdServer() {} +func (UnimplementedAdServer) testEmbeddedByValue() {} + +// UnsafeAdServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AdServer will +// result in compilation errors. +type UnsafeAdServer interface { + mustEmbedUnimplementedAdServer() +} + +func RegisterAdServer(s grpc.ServiceRegistrar, srv AdServer) { + // If the following call panics, it indicates UnimplementedAdServer 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(&Ad_ServiceDesc, srv) +} + +func _Ad_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdServer).Create(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Ad_Create_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdServer).Create(ctx, req.(*CreateReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Ad_Edit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EditReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdServer).Edit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Ad_Edit_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdServer).Edit(ctx, req.(*EditReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Ad_Items_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ItemsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdServer).Items(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Ad_Items_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdServer).Items(ctx, req.(*ItemsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Ad_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StatusReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdServer).Status(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Ad_Status_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdServer).Status(ctx, req.(*StatusReq)) + } + return interceptor(ctx, in, info, handler) +} + +// Ad_ServiceDesc is the grpc.ServiceDesc for Ad service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Ad_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "ad.Ad", + HandlerType: (*AdServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Create", + Handler: _Ad_Create_Handler, + }, + { + MethodName: "Edit", + Handler: _Ad_Edit_Handler, + }, + { + MethodName: "Items", + Handler: _Ad_Items_Handler, + }, + { + MethodName: "Status", + Handler: _Ad_Status_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ad/ad.proto", +} diff --git a/services/ad/Dockerfile b/services/ad/Dockerfile new file mode 100644 index 0000000..3b45dd3 --- /dev/null +++ b/services/ad/Dockerfile @@ -0,0 +1,39 @@ +FROM golang:1.26.5-alpine AS builder + +WORKDIR /src + +ENV GOPROXY=https://goproxy.cn,direct \ + CGO_ENABLED=0 \ + GOOS=linux \ + GOARCH=amd64 + +COPY pkg ./pkg +COPY go.mod go.sum ./ + +RUN --mount=type=cache,target=/go/pkg/mod \ + go mod download + +COPY rpc/ad/ ./rpc/ad/ +COPY services/ad/ ./services/ad/ + +WORKDIR /src/services/ad + +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + go build -ldflags="-s -w" -o /out/main ./ + +FROM alpine:3.22 + +WORKDIR /app + +ENV TZ=Asia/Shanghai + +RUN apk add --no-cache tzdata \ + && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo "Asia/Shanghai" > /etc/timezone + +COPY --from=builder /out/main . + +EXPOSE 10400 + +CMD ["./main", "-f", "etc/ad.yaml"] diff --git a/services/ad/ad.go b/services/ad/ad.go new file mode 100644 index 0000000..b296674 --- /dev/null +++ b/services/ad/ad.go @@ -0,0 +1,152 @@ +package main + +import ( + "flag" + "net" + "os" + "strconv" + + "lone-services/pkg/discovery" + "lone-services/pkg/modelbase" + "lone-services/pkg/mysql" + "lone-services/pkg/redis" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + ad "lone-services/rpc/ad/pb" + "lone-services/services/ad/internal/config" + "lone-services/services/ad/internal/server" + "lone-services/services/ad/internal/svc" + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/service" + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var configFile = flag.String("f", "etc/ad.yaml", "the config file") + +func main() { + flag.Parse() + var c config.Config + conf.MustLoad(*configFile, &c) + + nacosParam := utils.NacosConfig{ + Hosts: c.Nacos.Hosts, + NamespaceId: c.Nacos.NamespaceId, + Group: c.Nacos.Group, + ConfigID: c.Nacos.ConfigID, + } + utils.InitConfig(nacosParam) + + logConf := logx.LogConf{ + ServiceName: utils.GetConfigString("log.serviceName"), + Mode: utils.GetConfigString("log.mode"), + Encoding: utils.GetConfigString("log.encoding"), + Level: utils.GetConfigString("log.level"), + Path: utils.GetConfigString("log.path"), + KeepDays: utils.GetConfigInt("log.keepDays"), + MaxSize: utils.GetConfigInt("log.maxSize"), + MaxBackups: utils.GetConfigInt("log.maxBackups"), + Compress: utils.GetConfigBool("log.compress"), + } + logx.SetUp(logConf) + logx.AddWriter(logx.NewWriter(os.Stdout)) + + listenOn := utils.GetConfigString("base.listenOn") + mode := utils.GetConfigString("base.mode") + serviceName := utils.GetConfigString("base.name") + + if err := discovery.Init(discovery.Config{ + Hosts: c.Nacos.Hosts, + NamespaceId: c.Nacos.NamespaceId, + Group: c.Nacos.Group, + }); err != nil { + logx.Errorf("nacos init: %v", err) + os.Exit(1) + } + + port, err := listenPort(listenOn) + if err != nil { + logx.Errorf("parse ListenOn: %v", err) + os.Exit(1) + } + + if err := discovery.Register(discovery.Instance{ + ServiceName: serviceName, + IP: c.Nacos.RegisterIP, + Port: port, + Group: c.Nacos.Group, + }); err != nil { + logx.Errorf("nacos register: %v", err) + os.Exit(1) + } + logx.Infof("服务注册成功: %s:%d", c.Nacos.RegisterIP, port) + + defer func() { + if err := discovery.Deregister(); err != nil { + logx.Errorf("nacos deregister: %v", err) + } + }() + + db, err := mysql.New(mysql.Config{ + Host: utils.GetConfigString("mysql.host"), + Port: utils.GetConfigInt("mysql.port"), + User: utils.GetConfigString("mysql.user"), + Password: utils.GetConfigString("mysql.password"), + Database: utils.GetConfigString("mysql.database"), + Charset: utils.GetConfigString("mysql.charset"), + Prefix: utils.GetConfigString("mysql.prefix"), + ReadHost: utils.GetConfigString("mysql_read.host"), + ReadPort: utils.GetConfigInt("mysql_read.port"), + ReadUser: utils.GetConfigString("mysql_read.user"), + ReadPassword: utils.GetConfigString("mysql_read.password"), + ReadDatabase: utils.GetConfigString("mysql_read.database"), + }) + if err != nil { + logx.Errorf("mysql init: %v", err) + os.Exit(1) + } + + if err := redis.Init(redis.Config{ + Host: utils.GetConfigString("redis.host"), + Port: utils.GetConfigInt("redis.port"), + Password: utils.GetConfigString("redis.password"), + DB: utils.GetConfigInt("redis.db"), + }); err != nil { + logx.Errorf("redis init: %v", err) + os.Exit(1) + } + + debug := utils.GetConfigBool("mysql.debug") + modelbase.Init(db, modelbase.Config{Prefix: utils.GetConfigString("mysql.prefix"), Debug: debug}) + + rpcConf := zrpc.RpcServerConf{ + ListenOn: listenOn, + } + rpcConf.Mode = mode + + ctx := svc.NewServiceContext(c, db) + + s := zrpc.MustNewServer(rpcConf, func(grpcServer *grpc.Server) { + ad.RegisterAdServer(grpcServer, server.NewAdServer(ctx)) + if mode == service.DevMode || mode == service.TestMode { + reflection.Register(grpcServer) + } + }) + defer s.Stop() + + s.AddUnaryInterceptors(validate.UnaryServerInterceptor(validate.MustNew())) + + logx.Infof("Starting rpc server at %s...", listenOn) + s.Start() +} + +func listenPort(listenOn string) (uint64, error) { + _, portStr, err := net.SplitHostPort(listenOn) + if err != nil { + return 0, err + } + return strconv.ParseUint(portStr, 10, 64) +} diff --git a/services/ad/adclient/ad.go b/services/ad/adclient/ad.go new file mode 100644 index 0000000..e74b5a4 --- /dev/null +++ b/services/ad/adclient/ad.go @@ -0,0 +1,69 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.10.1 +// Source: ad.proto + +package adClient + +import ( + "context" + + "lone-services/rpc/ad/pb" + + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" +) + +type ( + CreateReq = ad.CreateReq + EditReq = ad.EditReq + Item = ad.Item + ItemsData = ad.ItemsData + ItemsReq = ad.ItemsReq + Response = ad.Response + StatusReq = ad.StatusReq + + Ad interface { + // 添加广告 + Create(ctx context.Context, in *CreateReq, opts ...grpc.CallOption) (*Response, error) + // 编辑广告 + Edit(ctx context.Context, in *EditReq, opts ...grpc.CallOption) (*Response, error) + // 广告列表 + Items(ctx context.Context, in *ItemsReq, opts ...grpc.CallOption) (*Response, error) + // 广告状态 + Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) + } + + defaultAd struct { + cli zrpc.Client + } +) + +func NewAd(cli zrpc.Client) Ad { + return &defaultAd{ + cli: cli, + } +} + +// 添加广告 +func (m *defaultAd) Create(ctx context.Context, in *CreateReq, opts ...grpc.CallOption) (*Response, error) { + client := ad.NewAdClient(m.cli.Conn()) + return client.Create(ctx, in, opts...) +} + +// 编辑广告 +func (m *defaultAd) Edit(ctx context.Context, in *EditReq, opts ...grpc.CallOption) (*Response, error) { + client := ad.NewAdClient(m.cli.Conn()) + return client.Edit(ctx, in, opts...) +} + +// 广告列表 +func (m *defaultAd) Items(ctx context.Context, in *ItemsReq, opts ...grpc.CallOption) (*Response, error) { + client := ad.NewAdClient(m.cli.Conn()) + return client.Items(ctx, in, opts...) +} + +// 广告状态 +func (m *defaultAd) Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) { + client := ad.NewAdClient(m.cli.Conn()) + return client.Status(ctx, in, opts...) +} diff --git a/services/ad/etc/ad.yaml b/services/ad/etc/ad.yaml new file mode 100644 index 0000000..72297d9 --- /dev/null +++ b/services/ad/etc/ad.yaml @@ -0,0 +1,7 @@ +Nacos: + Hosts: + - rnacos:8848 + NamespaceId: test + Group: LONE_SERVICES + RegisterIP: ad + ConfigID: ad \ No newline at end of file diff --git a/services/ad/internal/config/config.go b/services/ad/internal/config/config.go new file mode 100644 index 0000000..a1979dd --- /dev/null +++ b/services/ad/internal/config/config.go @@ -0,0 +1,13 @@ +package config + +type Config struct { + Nacos NacosConf +} + +type NacosConf struct { + Hosts []string + NamespaceId string `json:",optional"` + Group string `json:",optional"` + RegisterIP string `json:",optional"` + ConfigID string `json:",optional"` +} diff --git a/services/ad/internal/dao/ad.go b/services/ad/internal/dao/ad.go new file mode 100644 index 0000000..4a8e2a4 --- /dev/null +++ b/services/ad/internal/dao/ad.go @@ -0,0 +1,38 @@ +package dao + +const ( + AdStatusNormal uint8 = 1 // 正常 + AdStatusDisabled uint8 = 2 // 禁用 +) + +// type: 1、商城首页banner 2、商城首页视频 3、商城首页公告 4、商城首页教程 + +type AdCreate struct { + Id int `gorm:"column:id;primaryKey;autoIncrement"` + Type uint8 `gorm:"column:type"` + Image string `gorm:"column:image"` + Content string `gorm:"column:content"` + Url string `gorm:"column:url"` + AdminId int `gorm:"column:admin_id"` + AdminName string `gorm:"column:admin_name"` +} + +type AdInfo struct { + Id int `gorm:"column:id"` + Type uint8 `gorm:"column:type"` + Image string `gorm:"column:image"` + Content string `gorm:"column:content"` + Reason string `gorm:"column:reason"` + Status uint8 `gorm:"column:status"` + Url string `gorm:"column:url"` + UpdateTime string `gorm:"column:update_time"` + CreateTime string `gorm:"column:create_time"` +} + +type AdStatus struct { + Id int `gorm:"column:id;primaryKey"` + Reason string `gorm:"column:reason"` + Status uint8 `gorm:"column:status"` + AdminId int `gorm:"column:admin_id"` + AdminName string `gorm:"column:admin_name"` +} diff --git a/services/ad/internal/logic/convert.go b/services/ad/internal/logic/convert.go new file mode 100644 index 0000000..1b7d3de --- /dev/null +++ b/services/ad/internal/logic/convert.go @@ -0,0 +1,20 @@ +package logic + +import ( + ad "lone-services/rpc/ad/pb" + "lone-services/services/ad/internal/dao" +) + +func toAdItem(row dao.AdInfo) *ad.Item { + return &ad.Item{ + Id: int64(row.Id), + Type: uint32(row.Type), + Image: row.Image, + Content: row.Content, + Reason: row.Reason, + Status: uint32(row.Status), + Url: row.Url, + UpdateTime: row.UpdateTime, + CreateTime: row.CreateTime, + } +} diff --git a/services/ad/internal/logic/createLogic.go b/services/ad/internal/logic/createLogic.go new file mode 100644 index 0000000..8be6ae0 --- /dev/null +++ b/services/ad/internal/logic/createLogic.go @@ -0,0 +1,58 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/log" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + ad "lone-services/rpc/ad/pb" + "lone-services/services/ad/internal/dao" + "lone-services/services/ad/internal/model" + "lone-services/services/ad/internal/svc" + "lone-services/services/ad/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CreateLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateLogic { + return &CreateLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *CreateLogic) Create(in *ad.CreateReq) (*ad.Response, error) { + var req validator.AdCreateValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + + data := dao.AdCreate{ + Type: uint8(req.Type), + Image: req.Image, + Content: req.Content, + Url: req.Url, + AdminId: int(adminInfo.ID), + AdminName: adminInfo.Name, + } + if err := (model.AdModel{}.Init().Create(&data)); err != nil { + log.Errorf("create ad: %v", err) + return failResponse(utils.Fail), nil + } + + return okResponse(strconv.Itoa(data.Id)), nil +} diff --git a/services/ad/internal/logic/editLogic.go b/services/ad/internal/logic/editLogic.go new file mode 100644 index 0000000..491ed68 --- /dev/null +++ b/services/ad/internal/logic/editLogic.go @@ -0,0 +1,69 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/log" + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + ad "lone-services/rpc/ad/pb" + "lone-services/services/ad/internal/dao" + "lone-services/services/ad/internal/model" + "lone-services/services/ad/internal/svc" + "lone-services/services/ad/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type EditLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewEditLogic(ctx context.Context, svcCtx *svc.ServiceContext) *EditLogic { + return &EditLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *EditLogic) Edit(in *ad.EditReq) (*ad.Response, error) { + var req validator.AdEditValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + + w := modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(req.Id, 10)}} + var info dao.AdCreate + m := model.AdModel{}.Init() + if err := m.GetOne(w, &info); err != nil { + log.Errorf("edit ad get: %v", err) + return failResponse(utils.Fail), nil + } + if info.Id < utils.NumberOne { + return failResponse(utils.ErrorNotFund), nil + } + + info.Type = uint8(req.Type) + info.Image = req.Image + info.Content = req.Content + info.Url = req.Url + info.AdminId = int(adminInfo.ID) + info.AdminName = adminInfo.Name + + if _, err := m.Edit(w, &info); err != nil { + log.Errorf("edit ad: %v", err) + return failResponse(utils.Fail), nil + } + + return okResponse(utils.StringEmpty), nil +} diff --git a/services/ad/internal/logic/itemsLogic.go b/services/ad/internal/logic/itemsLogic.go new file mode 100644 index 0000000..373f8a8 --- /dev/null +++ b/services/ad/internal/logic/itemsLogic.go @@ -0,0 +1,70 @@ +package logic + +import ( + "context" + + "lone-services/pkg/log" + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + ad "lone-services/rpc/ad/pb" + "lone-services/services/ad/internal/dao" + "lone-services/services/ad/internal/model" + "lone-services/services/ad/internal/svc" + "lone-services/services/ad/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type ItemsLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewItemsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ItemsLogic { + return &ItemsLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *ItemsLogic) Items(in *ad.ItemsReq) (*ad.Response, error) { + var req validator.AdItemsValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + page := int(req.Page) + size := int(req.PageSize) + if page < modelbase.DefaultPage { + page = modelbase.DefaultPage + } + if size < modelbase.DefaultPage { + size = modelbase.DefaultSize + } + + w := modelbase.Params{ + Page: page, + Size: size, + Order: "id desc", + } + + var info []dao.AdInfo + result, err := model.AdModel{}.Init().Page(w, &info) + if err != nil { + log.Errorf("ad items: %v", err) + return failResponse(utils.Fail), nil + } + + items := make([]*ad.Item, 0, len(info)) + for _, row := range info { + items = append(items, toAdItem(row)) + } + + return okResponse(utils.StructToJson(&ad.ItemsData{ + Count: result.Count, + Items: items, + })), nil +} diff --git a/services/ad/internal/logic/response.go b/services/ad/internal/logic/response.go new file mode 100644 index 0000000..9059ef5 --- /dev/null +++ b/services/ad/internal/logic/response.go @@ -0,0 +1,28 @@ +package logic + +import ( + "lone-services/pkg/utils" + ad "lone-services/rpc/ad/pb" +) + +func okResponse(data string) *ad.Response { + return &ad.Response{ + Code: utils.Ok.Code, + Msg: utils.Ok.Msg, + Data: data, + } +} + +func failResponse(status utils.Status) *ad.Response { + return &ad.Response{ + Code: status.Code, + Msg: status.Msg, + } +} + +func outResponse(status utils.Status, msg string) *ad.Response { + return &ad.Response{ + Code: status.Code, + Msg: msg, + } +} diff --git a/services/ad/internal/logic/statusLogic.go b/services/ad/internal/logic/statusLogic.go new file mode 100644 index 0000000..e794144 --- /dev/null +++ b/services/ad/internal/logic/statusLogic.go @@ -0,0 +1,67 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/log" + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + ad "lone-services/rpc/ad/pb" + "lone-services/services/ad/internal/dao" + "lone-services/services/ad/internal/model" + "lone-services/services/ad/internal/svc" + "lone-services/services/ad/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type StatusLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *StatusLogic { + return &StatusLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *StatusLogic) Status(in *ad.StatusReq) (*ad.Response, error) { + var req validator.AdStatusValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + w := modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(req.Id, 10)}} + var info dao.AdStatus + m := model.AdModel{}.Init() + if err := m.GetOne(w, &info); err != nil { + log.Errorf("ad status get: %v", err) + return failResponse(utils.Fail), nil + } + if info.Id < utils.NumberOne { + return failResponse(utils.ErrorNotFund), nil + } + + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + + info.Reason = req.Reason + info.Status = uint8(req.Status) + info.AdminId = int(adminInfo.ID) + info.AdminName = adminInfo.Name + + if _, err := m.Edit(w, &info); err != nil { + log.Errorf("ad status edit: %v", err) + return failResponse(utils.Fail), nil + } + + return okResponse(utils.StringEmpty), nil +} diff --git a/services/ad/internal/model/ad_model.go b/services/ad/internal/model/ad_model.go new file mode 100644 index 0000000..f439af1 --- /dev/null +++ b/services/ad/internal/model/ad_model.go @@ -0,0 +1,23 @@ +package model + +import ( + "lone-services/pkg/modelbase" + "lone-services/services/ad/internal/dao" +) + +type AdModel struct { + modelbase.Base +} + +func (m AdModel) TableName() string { + return modelbase.Prefix() + "ad" +} + +func (m AdModel) Init() AdModel { + m.Table = m.TableName() + return m +} + +func (m AdModel) Create(data *dao.AdCreate) error { + return m.Base.Create(data) +} diff --git a/services/ad/internal/server/adServer.go b/services/ad/internal/server/adServer.go new file mode 100644 index 0000000..c1326ac --- /dev/null +++ b/services/ad/internal/server/adServer.go @@ -0,0 +1,48 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.10.1 +// Source: ad.proto + +package server + +import ( + "context" + + "lone-services/rpc/ad/pb" + "lone-services/services/ad/internal/logic" + "lone-services/services/ad/internal/svc" +) + +type AdServer struct { + svcCtx *svc.ServiceContext + ad.UnimplementedAdServer +} + +func NewAdServer(svcCtx *svc.ServiceContext) *AdServer { + return &AdServer{ + svcCtx: svcCtx, + } +} + +// 添加广告 +func (s *AdServer) Create(ctx context.Context, in *ad.CreateReq) (*ad.Response, error) { + l := logic.NewCreateLogic(ctx, s.svcCtx) + return l.Create(in) +} + +// 编辑广告 +func (s *AdServer) Edit(ctx context.Context, in *ad.EditReq) (*ad.Response, error) { + l := logic.NewEditLogic(ctx, s.svcCtx) + return l.Edit(in) +} + +// 广告列表 +func (s *AdServer) Items(ctx context.Context, in *ad.ItemsReq) (*ad.Response, error) { + l := logic.NewItemsLogic(ctx, s.svcCtx) + return l.Items(in) +} + +// 广告状态 +func (s *AdServer) Status(ctx context.Context, in *ad.StatusReq) (*ad.Response, error) { + l := logic.NewStatusLogic(ctx, s.svcCtx) + return l.Status(in) +} diff --git a/services/ad/internal/svc/servicecontext.go b/services/ad/internal/svc/servicecontext.go new file mode 100644 index 0000000..a31f07b --- /dev/null +++ b/services/ad/internal/svc/servicecontext.go @@ -0,0 +1,22 @@ +package svc + +import ( + "lone-services/pkg/utils" + "lone-services/services/ad/internal/config" + + "gorm.io/gorm" +) + +type ServiceContext struct { + Config config.Config + DB *gorm.DB + Prefix string +} + +func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { + return &ServiceContext{ + Config: c, + DB: db, + Prefix: utils.GetConfigString("mysql.prefix"), + } +} diff --git a/services/ad/run.toml b/services/ad/run.toml new file mode 100644 index 0000000..91b7b3a --- /dev/null +++ b/services/ad/run.toml @@ -0,0 +1,48 @@ +[base] + login_out_time=43200 + login_refresh_out_time=83200 + name = "ad-service" + listenOn = "0.0.0.0:10400" + mode = "dev" + super="1,2" +[log] + path = "logs" + serviceName = "ad-service" + mode = "file" + encoding = "plain" + level = "info" + keepDays = 7 + maxSize = 50 + maxBackups = 5 + compress = false +# 测试的地址 +[mysql] + host = '39.106.171.204' + port = 33066 + user = 'root' + password = 'MOLXRZNOU4Y4' + database = 'dms-ad' + charset = 'utf8mb4' + prefix = '' + debug = true +[mysql_read] + host = '39.106.171.204' + port = 33066 + user = 'root' + password = 'MOLXRZNOU4Y4' + database = 'dms-ad' + charset = 'utf8mb4' + prefix = '' + +[redis] + host = '39.106.171.204' + password = 'lLMLcuPpzSj' + port = 6379 + db = 0 +[log-redis] + host = '39.106.171.204' + password = 'lLMLcuPpzSj' + port = 6379 + db = 3 +[encrypt] + data_key = "u2t9T3luZtoRfhBstkFN6TiIMW38BA8a" #内容数据, \ No newline at end of file diff --git a/services/ad/validator/validator.go b/services/ad/validator/validator.go new file mode 100644 index 0000000..33b8763 --- /dev/null +++ b/services/ad/validator/validator.go @@ -0,0 +1,74 @@ +package validator + +import "lone-services/pkg/validate" + +type AdCreateValidator struct { + Type uint32 `validate:"required,oneof=1 2 3 4"` + Image string `validate:"required_without=Content,max=255"` + Content string `validate:"required_without=Image,max=255"` + Url string `validate:"max=255"` +} + +func (p AdCreateValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Type.required": "请选择类型", + "Type.oneof": "类型不对", + "Image.required_without": "图片与文本内容必须填写一个", + "Content.required_without": "图片与文本内容必须填写一个", + "Image.max": "图片长度不能超过255", + "Content.max": "内容长度不能超过255", + "Url.max": "链接长度不能超过255", + } +} + +type AdEditValidator struct { + Id int64 `validate:"required,gt=0"` + Type uint32 `validate:"required,oneof=1 2 3 4"` + Image string `validate:"required_without=Content,max=255"` + Content string `validate:"required_without=Image,max=255"` + Url string `validate:"max=255"` +} + +func (p AdEditValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.gt": "ID必须大于0", + "Type.required": "请选择类型", + "Type.oneof": "类型不对", + "Image.required_without": "图片与文本内容必须填写一个", + "Content.required_without": "图片与文本内容必须填写一个", + "Image.max": "图片长度不能超过255", + "Content.max": "内容长度不能超过255", + "Url.max": "链接长度不能超过255", + } +} + +type AdItemsValidator struct { + Page uint32 `validate:"omitempty,min=1"` + PageSize uint32 `validate:"omitempty,min=1,max=100"` +} + +func (p AdItemsValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Page.min": "页码最小为1", + "PageSize.min": "每页数量最小为1", + "PageSize.max": "每页数量最大为100", + } +} + +type AdStatusValidator struct { + Id int64 `validate:"required,gt=0"` + Status uint32 `validate:"required,oneof=1 2"` + Reason string `validate:"required_if=Status 2,max=255"` +} + +func (p AdStatusValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.gt": "ID必须大于0", + "Status.required": "状态不能为空", + "Status.oneof": "状态不对", + "Reason.required_if": "禁用状态,理由不能为空", + "Reason.max": "理由长度不能超过255", + } +}