From 0f88992db909aaa186f5df6646af114872c825e3 Mon Sep 17 00:00:00 2001 From: xiabin Date: Mon, 24 Feb 2025 17:27:51 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9app=20config=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/dev.yaml | 9 ++- app/admin_service/Dockerfile | 33 +++++++++ app/admin_service/admin_service.proto | 2 +- .../admin_service/admin_service.pb.go | 8 +-- .../internal/logic/get_app_list_logic.go | 72 ++++++++++++------- .../internal/svc/service_context.go | 38 +++++----- app/ecpm_service/internal/svc/ecpm_config.go | 12 ++-- .../internal/svc/service_context.go | 26 ++----- pkg/config/get_config.go | 15 ++-- 9 files changed, 135 insertions(+), 80 deletions(-) create mode 100644 app/admin_service/Dockerfile diff --git a/.gitea/workflows/dev.yaml b/.gitea/workflows/dev.yaml index 78e84f3..3abccba 100644 --- a/.gitea/workflows/dev.yaml +++ b/.gitea/workflows/dev.yaml @@ -20,6 +20,9 @@ jobs: - service: auth dockerfile: app/auth_service/Dockerfile image: auth + - service: admin + dockerfile: app/admin_service/Dockerfile + image: admin steps: - uses: https://gitea.youtukeji.com.cn/actions/checkout@v4 @@ -44,4 +47,8 @@ jobs: docker-compose down --remove-orphans docker-compose up -d --build env: - COMPOSE_PROJECT_NAME: youtu_grpc \ No newline at end of file + COMPOSE_PROJECT_NAME: youtu_grpc + steps: + - name: clean up + run: | + docker rmi $(docker images -f "dangling=true" -q) \ No newline at end of file diff --git a/app/admin_service/Dockerfile b/app/admin_service/Dockerfile new file mode 100644 index 0000000..4461c31 --- /dev/null +++ b/app/admin_service/Dockerfile @@ -0,0 +1,33 @@ +FROM golang:alpine AS builder + +LABEL stage=gobuilder + +ENV CGO_ENABLED=0 +ENV GOPROXY=https://goproxy.cn,direct + +RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories +RUN apk update --no-cache && apk add --no-cache tzdata +RUN apk add --no-cache git + +WORKDIR /build + +ADD go.mod . +ADD go.sum . +RUN go env -w GOPRIVATE=gitea.youtukeji.com.cn +RUN go mod download +COPY . . + +RUN go build -ldflags="-s -w" -o /app/admin ./app/admin_service/admin_service.go + + +FROM alpine + +COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai +ENV TZ=Asia/Shanghai + +WORKDIR /app +COPY --from=builder /app/admin /app/admin + +EXPOSE 8888 + +CMD ["/app/admin"] diff --git a/app/admin_service/admin_service.proto b/app/admin_service/admin_service.proto index e174aa6..487f37b 100644 --- a/app/admin_service/admin_service.proto +++ b/app/admin_service/admin_service.proto @@ -22,7 +22,7 @@ message GetAppListResponse { message AppInfo { int32 id = 1; - int32 type = 2; + string type = 2; string app_id = 3; string secret = 4; string remark = 5; diff --git a/app/admin_service/admin_service/admin_service.pb.go b/app/admin_service/admin_service/admin_service.pb.go index 5a0e168..2d72f72 100644 --- a/app/admin_service/admin_service/admin_service.pb.go +++ b/app/admin_service/admin_service/admin_service.pb.go @@ -192,7 +192,7 @@ func (x *GetAppListResponse) GetAppList() []*AppInfo { type AppInfo struct { state protoimpl.MessageState `protogen:"open.v1"` Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Type int32 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"` + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` AppId string `protobuf:"bytes,3,opt,name=app_id,json=appId,proto3" json:"app_id,omitempty"` Secret string `protobuf:"bytes,4,opt,name=secret,proto3" json:"secret,omitempty"` Remark string `protobuf:"bytes,5,opt,name=remark,proto3" json:"remark,omitempty"` @@ -239,11 +239,11 @@ func (x *AppInfo) GetId() int32 { return 0 } -func (x *AppInfo) GetType() int32 { +func (x *AppInfo) GetType() string { if x != nil { return x.Type } - return 0 + return "" } func (x *AppInfo) GetAppId() string { @@ -298,7 +298,7 @@ var file_admin_service_proto_rawDesc = string([]byte{ 0x2e, 0x41, 0x70, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x61, 0x70, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x9a, 0x01, 0x0a, 0x07, 0x41, 0x70, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x70, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, diff --git a/app/admin_service/internal/logic/get_app_list_logic.go b/app/admin_service/internal/logic/get_app_list_logic.go index 4a22b09..df3ce29 100644 --- a/app/admin_service/internal/logic/get_app_list_logic.go +++ b/app/admin_service/internal/logic/get_app_list_logic.go @@ -4,11 +4,12 @@ import ( "context" "encoding/json" "fmt" - "strconv" - "gitea.youtukeji.com.cn/youtu/youtu_grpc/app/admin_service/admin_service" + "slices" + "strings" "gitea.youtukeji.com.cn/youtu/youtu_grpc/app/admin_service/internal/svc" + clientv3 "go.etcd.io/etcd/client/v3" "github.com/zeromicro/go-zero/core/logx" ) @@ -27,53 +28,62 @@ func NewGetAppListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetApp } } -// 定义数据结构 +// EcpmConfig 定义数据结构 type EcpmConfig struct { - AppID string `json:"appId"` - ECPM int `json:"eCPM"` - IPU int `json:"IPU"` + AppID string `json:"appId"` + ECPM float32 `json:"eCPM"` + IPU uint32 `json:"IPU"` } type AppData struct { AppID string `json:"appId"` AppSecret string `json:"appSecret"` Type string `json:"type"` + Remark string `json:"remark"` } type MergedAppInfo struct { - AppID string `json:"appId"` - ECPM int `json:"eCPM,omitempty"` - IPU int `json:"IPU,omitempty"` - AppSecret string `json:"appSecret,omitempty"` - Type string `json:"type,omitempty"` + AppID string `json:"appId"` + ECPM float32 `json:"eCPM,omitempty"` + IPU uint32 `json:"IPU,omitempty"` + AppSecret string `json:"appSecret,omitempty"` + Type string `json:"type,omitempty"` + Remark string `json:"remark,omitempty"` } // GetAppList 获取app列表 func (l *GetAppListLogic) GetAppList(_ *admin_service.GetAppListRequest) (res *admin_service.GetAppListResponse, err error) { // 从ETCD获取ecpm配置 - ecpmResp, err := l.svcCtx.EtcdClient.Get(l.ctx, "/youtu/ecpm/config") + ecpmResp, err := l.svcCtx.EtcdClient.Get(l.ctx, "/youtu/app/ecpm/config", clientv3.WithPrefix()) if err != nil { return nil, fmt.Errorf("获取ecpm配置失败: %v", err) } - var ecpmConfigs []EcpmConfig - if len(ecpmResp.Kvs) > 0 { - if err := json.Unmarshal(ecpmResp.Kvs[0].Value, &ecpmConfigs); err != nil { + // 解析ecpm配置 + ecpmConfigs := make([]EcpmConfig, 0, len(ecpmResp.Kvs)) + for _, kv := range ecpmResp.Kvs { + cfg := EcpmConfig{} + if err := json.Unmarshal(kv.Value, &cfg); err != nil { return nil, fmt.Errorf("解析ecpm配置失败: %v", err) } + cfg.AppID = strings.TrimPrefix(string(kv.Key), "/youtu/app/ecpm/config/") + ecpmConfigs = append(ecpmConfigs, cfg) } // 从ETCD获取app数据 - appDataResp, err := l.svcCtx.EtcdClient.Get(l.ctx, "/youtu/appData") + appDataResp, err := l.svcCtx.EtcdClient.Get(l.ctx, "/youtu/app/account", clientv3.WithPrefix()) if err != nil { return nil, fmt.Errorf("获取app数据失败: %v", err) } - var appDatas []AppData - if len(appDataResp.Kvs) > 0 { - if err := json.Unmarshal(appDataResp.Kvs[0].Value, &appDatas); err != nil { + appDatas := make([]AppData, 0, len(appDataResp.Kvs)) + for _, kv := range appDataResp.Kvs { + appData := AppData{} + if err := json.Unmarshal(kv.Value, &appData); err != nil { return nil, fmt.Errorf("解析app数据失败: %v", err) } + appData.AppID = strings.TrimPrefix(string(kv.Key), "/youtu/app/account/") + appDatas = append(appDatas, appData) } // 创建合并映射 @@ -93,11 +103,13 @@ func (l *GetAppListLogic) GetAppList(_ *admin_service.GetAppListRequest) (res *a if info, exists := merged[app.AppID]; exists { info.AppSecret = app.AppSecret info.Type = app.Type + info.Remark = app.Remark } else { merged[app.AppID] = &MergedAppInfo{ AppID: app.AppID, AppSecret: app.AppSecret, Type: app.Type, + Remark: app.Remark, } } } @@ -112,17 +124,25 @@ func (l *GetAppListLogic) GetAppList(_ *admin_service.GetAppListRequest) (res *a appInfo := &admin_service.AppInfo{ AppId: info.AppID, Secret: info.AppSecret, - Ecpm: float32(info.ECPM), - Ipu: uint32(info.IPU), - } - - // 转换type为int32 - if typeInt, err := strconv.Atoi(info.Type); err == nil { - appInfo.Type = int32(typeInt) + Ecpm: info.ECPM, + Ipu: info.IPU, + Type: info.Type, + Remark: info.Remark, } res.AppList = append(res.AppList, appInfo) } + slices.SortFunc(res.AppList, func(i, j *admin_service.AppInfo) int { + if i.AppId < j.AppId { + return -1 + } + return 1 + }) + + for i, info := range res.AppList { + info.Id = int32(i + 1) + } + return res, nil } diff --git a/app/auth_service/internal/svc/service_context.go b/app/auth_service/internal/svc/service_context.go index 37efb68..05cb8d3 100644 --- a/app/auth_service/internal/svc/service_context.go +++ b/app/auth_service/internal/svc/service_context.go @@ -14,12 +14,12 @@ import ( "github.com/spf13/viper" "github.com/zeromicro/go-zero/core/conf" "github.com/zeromicro/go-zero/core/discov" - "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/zrpc" clientv3 "go.etcd.io/etcd/client/v3" "gorm.io/driver/mysql" "gorm.io/gorm" + "strings" ) type ServiceContext struct { @@ -73,7 +73,7 @@ type AppData struct { type AppDataList []AppData -const AppDataWatchKey = "/youtu/appData" +const AppDataWatchKey = "/youtu/app/account/" func (svc *ServiceContext) InitClient() { @@ -85,37 +85,37 @@ func (svc *ServiceContext) InitClient() { } go func() { - ch := make(chan []byte) + ch := make(chan config.WatchKV) go config.EtcdGetOneAndWatch(context.TODO(), cli, AppDataWatchKey, ch) //从通道中尝试取值(监视的信息) + for res := range ch { - var appDataArr AppDataList - err = json.Unmarshal(res, &appDataArr) + appData := AppData{} + err = json.Unmarshal(res.Value, &appData) if err != nil { logx.Errorf("etcd watch %s json.Unmarshal: %v", AppDataWatchKey, err) continue } - svc.SaveDW(appDataArr, svc.dwCache) + + appData.AppId = strings.TrimPrefix(res.Key, AppDataWatchKey) + svc.SaveDW(appData, svc.dwCache) } }() } -func (svc *ServiceContext) SaveDW(arr []AppData, dwCache cache.Cache) { - svc.Cli.Clear() +func (svc *ServiceContext) SaveDW(v AppData, dwCache cache.Cache) { //配置小程序cli(抖音&微信) - for _, v := range arr { - var c cli2.DWClient - switch v.Type { - case cli2.DouyinClientType: - c = cli2.NewDouYinApi(v.AppId, v.AppSecret, dwCache) - case cli2.WechatClientType: - c = cli2.NewWechatApi(v.AppId, v.AppSecret, dwCache) - default: - continue - } - svc.Cli.Set(v.AppId, c) + var c cli2.DWClient + switch v.Type { + case cli2.DouyinClientType: + c = cli2.NewDouYinApi(v.AppId, v.AppSecret, dwCache) + case cli2.WechatClientType: + c = cli2.NewWechatApi(v.AppId, v.AppSecret, dwCache) + default: + return } + svc.Cli.Set(v.AppId, c) } func (svc *ServiceContext) DeleteDWCache(appId string) (err error) { diff --git a/app/ecpm_service/internal/svc/ecpm_config.go b/app/ecpm_service/internal/svc/ecpm_config.go index 44bca79..e1163bf 100644 --- a/app/ecpm_service/internal/svc/ecpm_config.go +++ b/app/ecpm_service/internal/svc/ecpm_config.go @@ -41,13 +41,17 @@ func (c *EcpmConfigCli) SetAll(list []Ecpm) { } } -func (c *EcpmConfigCli) SetAllByJson(data []byte) { - var list []Ecpm +func (c *EcpmConfigCli) SetEcpm(list Ecpm) { + c.Map.Store(list.AppId, &list) +} + +func (c *EcpmConfigCli) SetAllByJson(appId string, data []byte) { + var list Ecpm err := json.Unmarshal(data, &list) if err != nil { return } - + list.AppId = appId slog.Info("set ecpm config", slog.AnyValue(list)) - c.SetAll(list) + c.SetEcpm(list) } diff --git a/app/ecpm_service/internal/svc/service_context.go b/app/ecpm_service/internal/svc/service_context.go index b85386d..4d1f10a 100644 --- a/app/ecpm_service/internal/svc/service_context.go +++ b/app/ecpm_service/internal/svc/service_context.go @@ -9,6 +9,7 @@ import ( "github.com/zeromicro/go-zero/core/discov" "github.com/zeromicro/go-zero/zrpc" clientv3 "go.etcd.io/etcd/client/v3" + "strings" ) type ServiceContext struct { @@ -32,7 +33,7 @@ func NewServiceContext(c config.Config) *ServiceContext { return svc } -const EcpmConfigWatchKey = "/youtu/ecpm/config" +const EcpmConfigWatchKey = "/youtu/app/ecpm/config/" func (svc *ServiceContext) initEtcd() { @@ -44,28 +45,13 @@ func (svc *ServiceContext) initEtcd() { panic(err) } - //获取ecpm配置 - res, err := cli.Get(context.Background(), EcpmConfigWatchKey) - if err != nil { - panic(err) - } + ch := make(chan config.WatchKV) + go config.EtcdGetOneAndWatch(context.Background(), cli, EcpmConfigWatchKey, ch) - //设置ecpm配置 - for _, kv := range res.Kvs { - svc.EcpmConfig.SetAllByJson(kv.Value) + for res := range ch { + svc.EcpmConfig.SetAllByJson(strings.TrimPrefix(res.Key, EcpmConfigWatchKey), res.Value) } - //监听etcd - go func() { - ch := cli.Watch(context.Background(), EcpmConfigWatchKey) - //从通道中尝试取值(监视的信息) - for res := range ch { - for _, evt := range res.Events { - svc.EcpmConfig.SetAllByJson(evt.Kv.Value) - } - } - }() - svc.etcdCli = cli } diff --git a/pkg/config/get_config.go b/pkg/config/get_config.go index 3968727..7c74137 100644 --- a/pkg/config/get_config.go +++ b/pkg/config/get_config.go @@ -77,21 +77,26 @@ func SetConfig(b, serverName string) (err error) { return } +type WatchKV struct { + Key string + Value []byte +} + // EtcdGetOneAndWatch 获取etcd配置并监听对应的key -func EtcdGetOneAndWatch(ctx context.Context, cli *clientv3.Client, key string, ch chan []byte) { +func EtcdGetOneAndWatch(ctx context.Context, cli *clientv3.Client, key string, ch chan WatchKV) { defer close(ch) - b, err := cli.Get(ctx, key) + b, err := cli.Get(ctx, key, clientv3.WithPrefix()) if err != nil { return } for _, kv := range b.Kvs { - ch <- kv.Value + ch <- WatchKV{Key: string(kv.Key), Value: kv.Value} } - resCh := cli.Watch(ctx, key) + resCh := cli.Watch(ctx, key, clientv3.WithPrefix()) for res := range resCh { for _, event := range res.Events { - ch <- event.Kv.Value + ch <- WatchKV{Key: string(event.Kv.Key), Value: event.Kv.Value} } }