From df62e4fae6aecbd005a7a0c26b5a223fe20df2af Mon Sep 17 00:00:00 2001 From: algotao Date: Thu, 16 Oct 2025 10:09:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=AE=9E=E9=AA=8C=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8B=89=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd.pb.go | 446 ++++++++++++++++++++++++++++++++++------ cmd.proto | 205 +++++++++++++++--- cmd/saastool/exp.go | 2 +- cmd/saastool/exp_get.go | 175 ++++++++++++++++ cmd/saastool/params.go | 32 +++ 5 files changed, 771 insertions(+), 89 deletions(-) diff --git a/cmd.pb.go b/cmd.pb.go index d74d374..9408810 100644 --- a/cmd.pb.go +++ b/cmd.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.8 +// protoc-gen-go v1.36.9 // protoc v5.29.4 // source: cmd.proto @@ -26,8 +26,8 @@ type BindType int32 const ( BindType_UnknownBindType BindType = 0 - BindType_AdgroupId BindType = 1 //广告 - BindType_AccountId BindType = 3 //广告主 + BindType_AdgroupId BindType = 1 // 广告 + BindType_AccountId BindType = 3 // 广告主 ) // Enum value maps for BindType. @@ -75,11 +75,11 @@ func (BindType) EnumDescriptor() ([]byte, []int) { type BindSourceType int32 const ( - BindSourceType_DefaultBindSourceType BindSourceType = 0 //广告主或未填写 - BindSourceType_ThirdPartyApi BindSourceType = 1 //第三方API - BindSourceType_ADQ BindSourceType = 2 //ADQ平台 - BindSourceType_MP BindSourceType = 3 //MP平台 - BindSourceType_MktApi BindSourceType = 4 //MarketingAPI + BindSourceType_DefaultBindSourceType BindSourceType = 0 // 广告主或未填写 + BindSourceType_ThirdPartyApi BindSourceType = 1 // 第三方API + BindSourceType_ADQ BindSourceType = 2 // ADQ平台 + BindSourceType_MP BindSourceType = 3 // MP平台 + BindSourceType_MktApi BindSourceType = 4 // MarketingAPI ) // Enum value maps for BindSourceType. @@ -157,6 +157,7 @@ const ( ErrorCode_DATA_ERROR ErrorCode = 201 // 数据错误 ErrorCode_CMD_ERROR ErrorCode = 202 // 命令行执行错误 ErrorCode_API_ERROR ErrorCode = 301 // 调用内部API错误 + ErrorCode_TARGET_ERROR ErrorCode = 401 // Target参数错误 ) // Enum value maps for ErrorCode. @@ -188,6 +189,7 @@ var ( 201: "DATA_ERROR", 202: "CMD_ERROR", 301: "API_ERROR", + 401: "TARGET_ERROR", } ErrorCode_value = map[string]int32{ "SUCC": 0, @@ -216,6 +218,7 @@ var ( "DATA_ERROR": 201, "CMD_ERROR": 202, "API_ERROR": 301, + "TARGET_ERROR": 401, } ) @@ -1043,11 +1046,9 @@ func (x *WriteItem) GetWriteFlagsWithExpire() *FlagsWithExpire { // Bytes 写入byte区域 type Bytes struct { - state protoimpl.MessageState `protogen:"open.v1"` - Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` // 写入的byte - Index_1 uint64 `protobuf:"varint,2,opt,name=index_1,json=index1,proto3" json:"index_1,omitempty"` // 写入byte的索引值(0..63) - // Deprecated: Marked as deprecated in cmd.proto. - Index_2 uint64 `protobuf:"varint,3,opt,name=index_2,json=index2,proto3" json:"index_2,omitempty"` // **已弃用 写入byte的索引值(64..127) + state protoimpl.MessageState `protogen:"open.v1"` + Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` // 写入的byte + Index_1 uint64 `protobuf:"varint,2,opt,name=index_1,json=index1,proto3" json:"index_1,omitempty"` // 写入byte的索引值(0..63) unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1096,14 +1097,6 @@ func (x *Bytes) GetIndex_1() uint64 { return 0 } -// Deprecated: Marked as deprecated in cmd.proto. -func (x *Bytes) GetIndex_2() uint64 { - if x != nil { - return x.Index_2 - } - return 0 -} - // Uint32s 写入uint32区域 type Uint32S struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -2094,10 +2087,26 @@ func (*ExpList) Descriptor() ([]byte, []int) { } // ExpGet 获取实验报表 +// select base_fields, {EXT_FIELDS} +// where day between {WHERE_BEGIN_DAY} and {WHERE_END_DAY} +// +// and expid in {WHERE_EXP_ID} +// and target = {WHERE_TARGET} +// and advertiser_id in {WHERE_ADVERTISER_ID} +// +// group by {GROUP_BY} type ExpGet struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ExtFields []string `protobuf:"bytes,1,rep,name=ext_fields,json=extFields,proto3" json:"ext_fields,omitempty"` // 扩展字段(除基础字段必然输出外,其余字段需在这里填写,也可以使用*输出全部扩展字段) + WhereBeginDay uint64 `protobuf:"varint,10,opt,name=where_begin_day,json=whereBeginDay,proto3" json:"where_begin_day,omitempty"` // 起始日期 + WhereEndDay uint64 `protobuf:"varint,11,opt,name=where_end_day,json=whereEndDay,proto3" json:"where_end_day,omitempty"` // 结束日期 + WhereExpId []uint32 `protobuf:"varint,12,rep,packed,name=where_exp_id,json=whereExpId,proto3" json:"where_exp_id,omitempty"` // 实验ID(1-10) + WhereTarget string `protobuf:"bytes,13,opt,name=where_target,json=whereTarget,proto3" json:"where_target,omitempty"` // 策略ID + WhereAdvertiserId []uint64 `protobuf:"varint,14,rep,packed,name=where_advertiser_id,json=whereAdvertiserId,proto3" json:"where_advertiser_id,omitempty"` // 广告主ID + GroupBy []string `protobuf:"bytes,20,rep,name=group_by,json=groupBy,proto3" json:"group_by,omitempty"` // 当前支持广告主ID(advertiser_id) + TotalFlag uint32 `protobuf:"varint,30,opt,name=TotalFlag,proto3" json:"TotalFlag,omitempty"` // 是否汇总 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExpGet) Reset() { @@ -2130,6 +2139,62 @@ func (*ExpGet) Descriptor() ([]byte, []int) { return file_cmd_proto_rawDescGZIP(), []int{24} } +func (x *ExpGet) GetExtFields() []string { + if x != nil { + return x.ExtFields + } + return nil +} + +func (x *ExpGet) GetWhereBeginDay() uint64 { + if x != nil { + return x.WhereBeginDay + } + return 0 +} + +func (x *ExpGet) GetWhereEndDay() uint64 { + if x != nil { + return x.WhereEndDay + } + return 0 +} + +func (x *ExpGet) GetWhereExpId() []uint32 { + if x != nil { + return x.WhereExpId + } + return nil +} + +func (x *ExpGet) GetWhereTarget() string { + if x != nil { + return x.WhereTarget + } + return "" +} + +func (x *ExpGet) GetWhereAdvertiserId() []uint64 { + if x != nil { + return x.WhereAdvertiserId + } + return nil +} + +func (x *ExpGet) GetGroupBy() []string { + if x != nil { + return x.GroupBy + } + return nil +} + +func (x *ExpGet) GetTotalFlag() uint32 { + if x != nil { + return x.TotalFlag + } + return 0 +} + // SaasRes 命令返回 type SaasRes struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -2880,11 +2945,11 @@ func (x *Binds) GetBinds() []*Bind { // Bind 绑定信息 type Bind struct { state protoimpl.MessageState `protogen:"open.v1"` - BindId int64 `protobuf:"varint,1,opt,name=bind_id,json=bindId,proto3" json:"bind_id,omitempty"` //绑定的ID - BindType BindType `protobuf:"varint,2,opt,name=bind_type,json=bindType,proto3,enum=saasapi.BindType" json:"bind_type,omitempty"` //绑定类型 - TargetId string `protobuf:"bytes,3,opt,name=target_id,json=targetId,proto3" json:"target_id,omitempty"` //策略ID - AccountId int64 `protobuf:"varint,4,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` //广告主ID - BindSource BindSourceType `protobuf:"varint,5,opt,name=bind_source,json=bindSource,proto3,enum=saasapi.BindSourceType" json:"bind_source,omitempty"` //绑定操作来源 + BindId int64 `protobuf:"varint,1,opt,name=bind_id,json=bindId,proto3" json:"bind_id,omitempty"` // 绑定的ID + BindType BindType `protobuf:"varint,2,opt,name=bind_type,json=bindType,proto3,enum=saasapi.BindType" json:"bind_type,omitempty"` // 绑定类型 + TargetId string `protobuf:"bytes,3,opt,name=target_id,json=targetId,proto3" json:"target_id,omitempty"` // 策略ID + AccountId int64 `protobuf:"varint,4,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` // 广告主ID + BindSource BindSourceType `protobuf:"varint,5,opt,name=bind_source,json=bindSource,proto3,enum=saasapi.BindSourceType" json:"bind_source,omitempty"` // 绑定操作来源 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2957,9 +3022,9 @@ func (x *Bind) GetBindSource() BindSourceType { // BindSetRes 设置绑定返回 type BindSetRes struct { state protoimpl.MessageState `protogen:"open.v1"` - SuccessNum int32 `protobuf:"varint,1,opt,name=success_num,json=successNum,proto3" json:"success_num,omitempty"` //成功数 - ErrorNum int32 `protobuf:"varint,2,opt,name=error_num,json=errorNum,proto3" json:"error_num,omitempty"` //错误数 - Errors []*BindError `protobuf:"bytes,3,rep,name=errors,proto3" json:"errors,omitempty"` //绑定错误的记录 + SuccessNum int32 `protobuf:"varint,1,opt,name=success_num,json=successNum,proto3" json:"success_num,omitempty"` // 成功数 + ErrorNum int32 `protobuf:"varint,2,opt,name=error_num,json=errorNum,proto3" json:"error_num,omitempty"` // 错误数 + Errors []*BindError `protobuf:"bytes,3,rep,name=errors,proto3" json:"errors,omitempty"` // 绑定错误的记录 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3018,9 +3083,9 @@ func (x *BindSetRes) GetErrors() []*BindError { // BindDeleteRes 删除绑定返回 type BindDeleteRes struct { state protoimpl.MessageState `protogen:"open.v1"` - SuccessNum int32 `protobuf:"varint,1,opt,name=success_num,json=successNum,proto3" json:"success_num,omitempty"` //成功数 - ErrorNum int32 `protobuf:"varint,2,opt,name=error_num,json=errorNum,proto3" json:"error_num,omitempty"` //错误数 - Errors []*BindError `protobuf:"bytes,3,rep,name=errors,proto3" json:"errors,omitempty"` //绑定错误的记录 + SuccessNum int32 `protobuf:"varint,1,opt,name=success_num,json=successNum,proto3" json:"success_num,omitempty"` // 成功数 + ErrorNum int32 `protobuf:"varint,2,opt,name=error_num,json=errorNum,proto3" json:"error_num,omitempty"` // 错误数 + Errors []*BindError `protobuf:"bytes,3,rep,name=errors,proto3" json:"errors,omitempty"` // 绑定错误的记录 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3079,9 +3144,9 @@ func (x *BindDeleteRes) GetErrors() []*BindError { // BindError 绑定错误信息 type BindError struct { state protoimpl.MessageState `protogen:"open.v1"` - BindId int64 `protobuf:"varint,1,opt,name=bind_id,json=bindId,proto3" json:"bind_id,omitempty"` //错误绑定的绑定ID - BindType int32 `protobuf:"varint,2,opt,name=bind_type,json=bindType,proto3" json:"bind_type,omitempty"` //绑定类型 - Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` //错误绑定原因 + BindId int64 `protobuf:"varint,1,opt,name=bind_id,json=bindId,proto3" json:"bind_id,omitempty"` // 错误绑定的绑定ID + BindType int32 `protobuf:"varint,2,opt,name=bind_type,json=bindType,proto3" json:"bind_type,omitempty"` // 绑定类型 + Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` // 错误绑定原因 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3246,7 +3311,7 @@ func (*ScriptUpdateRes) Descriptor() ([]byte, []int) { // ExpListRes 实验列表返回 type ExpListRes struct { state protoimpl.MessageState `protogen:"open.v1"` - Buckets []*ExpBucket `protobuf:"bytes,1,rep,name=buckets,proto3" json:"buckets,omitempty"` //实验桶 + Buckets []*ExpBucket `protobuf:"bytes,1,rep,name=buckets,proto3" json:"buckets,omitempty"` // 实验桶 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3290,9 +3355,9 @@ func (x *ExpListRes) GetBuckets() []*ExpBucket { type ExpBucket struct { state protoimpl.MessageState `protogen:"open.v1"` - BucketId uint32 `protobuf:"varint,1,opt,name=bucket_id,json=bucketId,proto3" json:"bucket_id,omitempty"` //分桶号 - PtExpId uint32 `protobuf:"varint,2,opt,name=pt_exp_id,json=ptExpId,proto3" json:"pt_exp_id,omitempty"` //平台实验ID - Percent uint32 `protobuf:"varint,3,opt,name=percent,proto3" json:"percent,omitempty"` //流量百分比 + BucketId uint32 `protobuf:"varint,1,opt,name=bucket_id,json=bucketId,proto3" json:"bucket_id,omitempty"` // 分桶号 + PtExpId uint32 `protobuf:"varint,2,opt,name=pt_exp_id,json=ptExpId,proto3" json:"pt_exp_id,omitempty"` // 平台实验ID + Percent uint32 `protobuf:"varint,3,opt,name=percent,proto3" json:"percent,omitempty"` // 流量百分比 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3351,6 +3416,7 @@ func (x *ExpBucket) GetPercent() uint32 { // ExpGetRes 实验报表返回 type ExpGetRes struct { state protoimpl.MessageState `protogen:"open.v1"` + Expdata []*ExpData `protobuf:"bytes,1,rep,name=expdata,proto3" json:"expdata,omitempty"` // 实验数据 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3385,6 +3451,213 @@ func (*ExpGetRes) Descriptor() ([]byte, []int) { return file_cmd_proto_rawDescGZIP(), []int{42} } +func (x *ExpGetRes) GetExpdata() []*ExpData { + if x != nil { + return x.Expdata + } + return nil +} + +type ExpData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Time uint64 `protobuf:"varint,1,opt,name=time,proto3" json:"time,omitempty"` // 日期 + ExpId uint32 `protobuf:"varint,2,opt,name=ExpId,proto3" json:"ExpId,omitempty"` // 实验ID + BaseFields *ExpBaseFields `protobuf:"bytes,3,opt,name=base_fields,json=baseFields,proto3" json:"base_fields,omitempty"` // 基础字段 + ExtFields map[string]float64 `protobuf:"bytes,4,rep,name=ext_fields,json=extFields,proto3" json:"ext_fields,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed64,2,opt,name=value"` // 扩展字段 + Group map[string]uint64 `protobuf:"bytes,5,rep,name=group,proto3" json:"group,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` // 分组 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExpData) Reset() { + *x = ExpData{} + mi := &file_cmd_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExpData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExpData) ProtoMessage() {} + +func (x *ExpData) ProtoReflect() protoreflect.Message { + mi := &file_cmd_proto_msgTypes[43] + 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 ExpData.ProtoReflect.Descriptor instead. +func (*ExpData) Descriptor() ([]byte, []int) { + return file_cmd_proto_rawDescGZIP(), []int{43} +} + +func (x *ExpData) GetTime() uint64 { + if x != nil { + return x.Time + } + return 0 +} + +func (x *ExpData) GetExpId() uint32 { + if x != nil { + return x.ExpId + } + return 0 +} + +func (x *ExpData) GetBaseFields() *ExpBaseFields { + if x != nil { + return x.BaseFields + } + return nil +} + +func (x *ExpData) GetExtFields() map[string]float64 { + if x != nil { + return x.ExtFields + } + return nil +} + +func (x *ExpData) GetGroup() map[string]uint64 { + if x != nil { + return x.Group + } + return nil +} + +type ExpBaseFields struct { + state protoimpl.MessageState `protogen:"open.v1"` + Cost float64 `protobuf:"fixed64,1,opt,name=cost,proto3" json:"cost,omitempty"` // 花费 + Exposure int64 `protobuf:"varint,2,opt,name=exposure,proto3" json:"exposure,omitempty"` // 曝光量 + Click int64 `protobuf:"varint,3,opt,name=click,proto3" json:"click,omitempty"` // 点击量 + Cpm float64 `protobuf:"fixed64,4,opt,name=cpm,proto3" json:"cpm,omitempty"` // 单次曝光成本 + Cpc float64 `protobuf:"fixed64,5,opt,name=cpc,proto3" json:"cpc,omitempty"` // 单次点击成本 + Cpa float64 `protobuf:"fixed64,6,opt,name=cpa,proto3" json:"cpa,omitempty"` // 单次转化成本 + Ctr float64 `protobuf:"fixed64,7,opt,name=ctr,proto3" json:"ctr,omitempty"` // 点击率 + Cvr float64 `protobuf:"fixed64,8,opt,name=cvr,proto3" json:"cvr,omitempty"` // 浅层转化率 + CvrSecond float64 `protobuf:"fixed64,9,opt,name=cvr_second,json=cvrSecond,proto3" json:"cvr_second,omitempty"` // 深层转化率 + Conversion int64 `protobuf:"varint,10,opt,name=conversion,proto3" json:"conversion,omitempty"` // 浅层转化量 + ConversionSecond int64 `protobuf:"varint,11,opt,name=conversion_second,json=conversionSecond,proto3" json:"conversion_second,omitempty"` // 深层转化量 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExpBaseFields) Reset() { + *x = ExpBaseFields{} + mi := &file_cmd_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExpBaseFields) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExpBaseFields) ProtoMessage() {} + +func (x *ExpBaseFields) ProtoReflect() protoreflect.Message { + mi := &file_cmd_proto_msgTypes[44] + 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 ExpBaseFields.ProtoReflect.Descriptor instead. +func (*ExpBaseFields) Descriptor() ([]byte, []int) { + return file_cmd_proto_rawDescGZIP(), []int{44} +} + +func (x *ExpBaseFields) GetCost() float64 { + if x != nil { + return x.Cost + } + return 0 +} + +func (x *ExpBaseFields) GetExposure() int64 { + if x != nil { + return x.Exposure + } + return 0 +} + +func (x *ExpBaseFields) GetClick() int64 { + if x != nil { + return x.Click + } + return 0 +} + +func (x *ExpBaseFields) GetCpm() float64 { + if x != nil { + return x.Cpm + } + return 0 +} + +func (x *ExpBaseFields) GetCpc() float64 { + if x != nil { + return x.Cpc + } + return 0 +} + +func (x *ExpBaseFields) GetCpa() float64 { + if x != nil { + return x.Cpa + } + return 0 +} + +func (x *ExpBaseFields) GetCtr() float64 { + if x != nil { + return x.Ctr + } + return 0 +} + +func (x *ExpBaseFields) GetCvr() float64 { + if x != nil { + return x.Cvr + } + return 0 +} + +func (x *ExpBaseFields) GetCvrSecond() float64 { + if x != nil { + return x.CvrSecond + } + return 0 +} + +func (x *ExpBaseFields) GetConversion() int64 { + if x != nil { + return x.Conversion + } + return 0 +} + +func (x *ExpBaseFields) GetConversionSecond() int64 { + if x != nil { + return x.ConversionSecond + } + return 0 +} + var File_cmd_proto protoreflect.FileDescriptor const file_cmd_proto_rawDesc = "" + @@ -3433,11 +3706,10 @@ const file_cmd_proto_rawDesc = "" + "\vwrite_bytes\x18\x02 \x01(\v2\x0e.saasapi.BytesR\n" + "writeBytes\x125\n" + "\rwrite_uint32s\x18\x03 \x01(\v2\x10.saasapi.Uint32sR\fwriteUint32s\x12O\n" + - "\x17write_flags_with_expire\x18\x04 \x01(\v2\x18.saasapi.FlagsWithExpireR\x14writeFlagsWithExpire\"S\n" + + "\x17write_flags_with_expire\x18\x04 \x01(\v2\x18.saasapi.FlagsWithExpireR\x14writeFlagsWithExpire\"6\n" + "\x05Bytes\x12\x14\n" + "\x05bytes\x18\x01 \x01(\fR\x05bytes\x12\x17\n" + - "\aindex_1\x18\x02 \x01(\x04R\x06index1\x12\x1b\n" + - "\aindex_2\x18\x03 \x01(\x04B\x02\x18\x01R\x06index2\"<\n" + + "\aindex_1\x18\x02 \x01(\x04R\x06index1\"<\n" + "\aUint32s\x12\x18\n" + "\auint32s\x18\x01 \x03(\rR\auint32s\x12\x17\n" + "\aindex_1\x18\x02 \x01(\x04R\x06index1\"o\n" + @@ -3515,8 +3787,19 @@ const file_cmd_proto_rawDesc = "" + "\rserver_openid\x18\x04 \x01(\tR\fserverOpenid\x12\x1b\n" + "\x02os\x18\x05 \x01(\x0e2\v.saasapi.OSR\x02os\"\x0e\n" + "\fScriptUpdate\"\t\n" + - "\aExpList\"\b\n" + - "\x06ExpGet\"\xa9\a\n" + + "\aExpList\"\xa1\x02\n" + + "\x06ExpGet\x12\x1d\n" + + "\n" + + "ext_fields\x18\x01 \x03(\tR\textFields\x12&\n" + + "\x0fwhere_begin_day\x18\n" + + " \x01(\x04R\rwhereBeginDay\x12\"\n" + + "\rwhere_end_day\x18\v \x01(\x04R\vwhereEndDay\x12 \n" + + "\fwhere_exp_id\x18\f \x03(\rR\n" + + "whereExpId\x12!\n" + + "\fwhere_target\x18\r \x01(\tR\vwhereTarget\x12.\n" + + "\x13where_advertiser_id\x18\x0e \x03(\x04R\x11whereAdvertiserId\x12\x19\n" + + "\bgroup_by\x18\x14 \x03(\tR\agroupBy\x12\x1c\n" + + "\tTotalFlag\x18\x1e \x01(\rR\tTotalFlag\"\xa9\a\n" + "\aSaasRes\x12&\n" + "\x04code\x18\x01 \x01(\x0e2\x12.saasapi.ErrorCodeR\x04code\x12\x16\n" + "\x06status\x18\x02 \x01(\tR\x06status\x12-\n" + @@ -3605,8 +3888,40 @@ const file_cmd_proto_rawDesc = "" + "\tExpBucket\x12\x1b\n" + "\tbucket_id\x18\x01 \x01(\rR\bbucketId\x12\x1a\n" + "\tpt_exp_id\x18\x02 \x01(\rR\aptExpId\x12\x18\n" + - "\apercent\x18\x03 \x01(\rR\apercent\"\v\n" + - "\tExpGetRes*=\n" + + "\apercent\x18\x03 \x01(\rR\apercent\"7\n" + + "\tExpGetRes\x12*\n" + + "\aexpdata\x18\x01 \x03(\v2\x10.saasapi.ExpDataR\aexpdata\"\xd7\x02\n" + + "\aExpData\x12\x12\n" + + "\x04time\x18\x01 \x01(\x04R\x04time\x12\x14\n" + + "\x05ExpId\x18\x02 \x01(\rR\x05ExpId\x127\n" + + "\vbase_fields\x18\x03 \x01(\v2\x16.saasapi.ExpBaseFieldsR\n" + + "baseFields\x12>\n" + + "\n" + + "ext_fields\x18\x04 \x03(\v2\x1f.saasapi.ExpData.ExtFieldsEntryR\textFields\x121\n" + + "\x05group\x18\x05 \x03(\v2\x1b.saasapi.ExpData.GroupEntryR\x05group\x1a<\n" + + "\x0eExtFieldsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\x01R\x05value:\x028\x01\x1a8\n" + + "\n" + + "GroupEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\x04R\x05value:\x028\x01\"\x9b\x02\n" + + "\rExpBaseFields\x12\x12\n" + + "\x04cost\x18\x01 \x01(\x01R\x04cost\x12\x1a\n" + + "\bexposure\x18\x02 \x01(\x03R\bexposure\x12\x14\n" + + "\x05click\x18\x03 \x01(\x03R\x05click\x12\x10\n" + + "\x03cpm\x18\x04 \x01(\x01R\x03cpm\x12\x10\n" + + "\x03cpc\x18\x05 \x01(\x01R\x03cpc\x12\x10\n" + + "\x03cpa\x18\x06 \x01(\x01R\x03cpa\x12\x10\n" + + "\x03ctr\x18\a \x01(\x01R\x03ctr\x12\x10\n" + + "\x03cvr\x18\b \x01(\x01R\x03cvr\x12\x1d\n" + + "\n" + + "cvr_second\x18\t \x01(\x01R\tcvrSecond\x12\x1e\n" + + "\n" + + "conversion\x18\n" + + " \x01(\x03R\n" + + "conversion\x12+\n" + + "\x11conversion_second\x18\v \x01(\x03R\x10conversionSecond*=\n" + "\bBindType\x12\x13\n" + "\x0fUnknownBindType\x10\x00\x12\r\n" + "\tAdgroupId\x10\x01\x12\r\n" + @@ -3617,7 +3932,7 @@ const file_cmd_proto_rawDesc = "" + "\x03ADQ\x10\x02\x12\x06\n" + "\x02MP\x10\x03\x12\n" + "\n" + - "\x06MktApi\x10\x04*\xfa\x03\n" + + "\x06MktApi\x10\x04*\x8d\x04\n" + "\tErrorCode\x12\b\n" + "\x04SUCC\x10\x00\x12\x13\n" + "\x0fINVALID_ACCOUNT\x10e\x12\x15\n" + @@ -3646,7 +3961,8 @@ const file_cmd_proto_rawDesc = "" + "\n" + "DATA_ERROR\x10\xc9\x01\x12\x0e\n" + "\tCMD_ERROR\x10\xca\x01\x12\x0e\n" + - "\tAPI_ERROR\x10\xad\x02*\x16\n" + + "\tAPI_ERROR\x10\xad\x02\x12\x11\n" + + "\fTARGET_ERROR\x10\x91\x03*\x16\n" + "\fCmdErrorCode\x12\x06\n" + "\x02OK\x10\x00*^\n" + "\n" + @@ -3683,7 +3999,7 @@ func file_cmd_proto_rawDescGZIP() []byte { } var file_cmd_proto_enumTypes = make([]protoimpl.EnumInfo, 7) -var file_cmd_proto_msgTypes = make([]protoimpl.MessageInfo, 44) +var file_cmd_proto_msgTypes = make([]protoimpl.MessageInfo, 48) var file_cmd_proto_goTypes = []any{ (BindType)(0), // 0: saasapi.BindType (BindSourceType)(0), // 1: saasapi.BindSourceType @@ -3735,7 +4051,11 @@ var file_cmd_proto_goTypes = []any{ (*ExpListRes)(nil), // 47: saasapi.ExpListRes (*ExpBucket)(nil), // 48: saasapi.ExpBucket (*ExpGetRes)(nil), // 49: saasapi.ExpGetRes - nil, // 50: saasapi.TargetListRes.TargetListEntry + (*ExpData)(nil), // 50: saasapi.ExpData + (*ExpBaseFields)(nil), // 51: saasapi.ExpBaseFields + nil, // 52: saasapi.TargetListRes.TargetListEntry + nil, // 53: saasapi.ExpData.ExtFieldsEntry + nil, // 54: saasapi.ExpData.GroupEntry } var file_cmd_proto_depIdxs = []int32{ 8, // 0: saasapi.SaasReq.info:type_name -> saasapi.Info @@ -3791,19 +4111,23 @@ var file_cmd_proto_depIdxs = []int32{ 3, // 50: saasapi.ValueItem.cmd_code:type_name -> saasapi.CmdErrorCode 16, // 51: saasapi.ValueItem.flags_with_expire:type_name -> saasapi.FlagWithExpire 18, // 52: saasapi.TaskListRes.tasks:type_name -> saasapi.Task - 50, // 53: saasapi.TargetListRes.target_list:type_name -> saasapi.TargetListRes.TargetListEntry + 52, // 53: saasapi.TargetListRes.target_list:type_name -> saasapi.TargetListRes.TargetListEntry 41, // 54: saasapi.Binds.binds:type_name -> saasapi.Bind 0, // 55: saasapi.Bind.bind_type:type_name -> saasapi.BindType 1, // 56: saasapi.Bind.bind_source:type_name -> saasapi.BindSourceType 44, // 57: saasapi.BindSetRes.errors:type_name -> saasapi.BindError 44, // 58: saasapi.BindDeleteRes.errors:type_name -> saasapi.BindError 48, // 59: saasapi.ExpListRes.buckets:type_name -> saasapi.ExpBucket - 40, // 60: saasapi.TargetListRes.TargetListEntry.value:type_name -> saasapi.Binds - 61, // [61:61] is the sub-list for method output_type - 61, // [61:61] is the sub-list for method input_type - 61, // [61:61] is the sub-list for extension type_name - 61, // [61:61] is the sub-list for extension extendee - 0, // [0:61] is the sub-list for field type_name + 50, // 60: saasapi.ExpGetRes.expdata:type_name -> saasapi.ExpData + 51, // 61: saasapi.ExpData.base_fields:type_name -> saasapi.ExpBaseFields + 53, // 62: saasapi.ExpData.ext_fields:type_name -> saasapi.ExpData.ExtFieldsEntry + 54, // 63: saasapi.ExpData.group:type_name -> saasapi.ExpData.GroupEntry + 40, // 64: saasapi.TargetListRes.TargetListEntry.value:type_name -> saasapi.Binds + 65, // [65:65] is the sub-list for method output_type + 65, // [65:65] is the sub-list for method input_type + 65, // [65:65] is the sub-list for extension type_name + 65, // [65:65] is the sub-list for extension extendee + 0, // [0:65] is the sub-list for field type_name } func init() { file_cmd_proto_init() } @@ -3852,7 +4176,7 @@ func file_cmd_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_cmd_proto_rawDesc), len(file_cmd_proto_rawDesc)), NumEnums: 7, - NumMessages: 44, + NumMessages: 48, NumExtensions: 0, NumServices: 0, }, diff --git a/cmd.proto b/cmd.proto index 0f48378..7ae8d51 100644 --- a/cmd.proto +++ b/cmd.proto @@ -189,8 +189,21 @@ message ExpList { } // ExpGet 获取实验报表 +// select base_fields, {EXT_FIELDS} +// where day between {WHERE_BEGIN_DAY} and {WHERE_END_DAY} +// and expid in {WHERE_EXP_ID} +// and target = {WHERE_TARGET} +// and advertiser_id in {WHERE_ADVERTISER_ID} +// group by {GROUP_BY} message ExpGet { - + repeated string ext_fields = 1; // 扩展字段(除基础字段必然输出外,其余字段需在这里填写,也可以使用*输出全部扩展字段) + uint64 where_begin_day = 10; // 起始日期 + uint64 where_end_day = 11; // 结束日期 + repeated uint32 where_exp_id = 12; // 实验ID(1-10) + string where_target = 13; // 策略ID + repeated uint64 where_advertiser_id = 14; // 广告主ID + repeated string group_by = 20; // 当前支持广告主ID(advertiser_id) + uint32 TotalFlag = 30; // 是否汇总 } // SaasRes 命令返回 @@ -275,49 +288,49 @@ message Binds { // Bind 绑定信息 message Bind { - int64 bind_id = 1; //绑定的ID - BindType bind_type = 2; //绑定类型 - string target_id = 3; //策略ID - int64 account_id = 4; //广告主ID - BindSourceType bind_source = 5; //绑定操作来源 + int64 bind_id = 1; // 绑定的ID + BindType bind_type = 2; // 绑定类型 + string target_id = 3; // 策略ID + int64 account_id = 4; // 广告主ID + BindSourceType bind_source = 5; // 绑定操作来源 } // BindType 绑定类型 enum BindType { UnknownBindType = 0; - AdgroupId = 1; //广告 - AccountId = 3; //广告主 + AdgroupId = 1; // 广告 + AccountId = 3; // 广告主 } // BindSourceType 绑定操作来源 enum BindSourceType { - DefaultBindSourceType = 0; //广告主或未填写 - ThirdPartyApi = 1; //第三方API - ADQ = 2; //ADQ平台 - MP = 3; //MP平台 - MktApi = 4; //MarketingAPI + DefaultBindSourceType = 0; // 广告主或未填写 + ThirdPartyApi = 1; // 第三方API + ADQ = 2; // ADQ平台 + MP = 3; // MP平台 + MktApi = 4; // MarketingAPI } // BindSetRes 设置绑定返回 message BindSetRes { - int32 success_num = 1; //成功数 - int32 error_num = 2; //错误数 - repeated BindError errors = 3; //绑定错误的记录 + int32 success_num = 1; // 成功数 + int32 error_num = 2; // 错误数 + repeated BindError errors = 3; // 绑定错误的记录 } // BindDeleteRes 删除绑定返回 message BindDeleteRes { - int32 success_num = 1; //成功数 - int32 error_num = 2; //错误数 - repeated BindError errors = 3; //绑定错误的记录 + int32 success_num = 1; // 成功数 + int32 error_num = 2; // 错误数 + repeated BindError errors = 3; // 绑定错误的记录 } // BindError 绑定错误信息 message BindError { - int64 bind_id = 1; //错误绑定的绑定ID - int32 bind_type = 2; //绑定类型 - string reason = 3; //错误绑定原因 + int64 bind_id = 1; // 错误绑定的绑定ID + int32 bind_type = 2; // 绑定类型 + string reason = 3; // 错误绑定原因 } @@ -335,20 +348,156 @@ message ScriptUpdateRes { // ExpListRes 实验列表返回 message ExpListRes { - repeated ExpBucket buckets = 1; //实验桶 + repeated ExpBucket buckets = 1; // 实验桶 } message ExpBucket { - uint32 bucket_id = 1; //分桶号 - uint32 pt_exp_id = 2; //平台实验ID - uint32 percent = 3; //流量百分比 + uint32 bucket_id = 1; // 分桶号 + uint32 pt_exp_id = 2; // 平台实验ID + uint32 percent = 3; // 流量百分比 } // ExpGetRes 实验报表返回 message ExpGetRes { - + repeated ExpData expdata = 1; // 实验数据 } +message ExpData { + uint64 time = 1; // 日期 + uint32 ExpId = 2; // 实验ID + ExpBaseFields base_fields = 3; // 基础字段 + map ext_fields = 4; // 扩展字段 + map group = 5; // 分组 +} + +message ExpBaseFields { + double cost = 1; // 花费 + int64 exposure = 2; // 曝光量 + int64 click = 3; // 点击量 + double cpm = 4; // 单次曝光成本 + double cpc = 5; // 单次点击成本 + double cpa = 6; // 单次转化成本 + double ctr = 7; // 点击率 + double cvr = 8; // 浅层转化率 + double cvr_second = 9; // 深层转化率 + int64 conversion = 10; // 浅层转化量 + int64 conversion_second = 11; // 深层转化量 +} + +/* +type RtaResExpGetRecord struct { + Time int32 `json:"time"` // 时间 + ExpId int64 `json:"exp_id"` // 实验ID + GroupInfo map[string]uint64 `json:"group_info"` // GroupBy信息 + Cost float64 `json:"cost"` // 消耗(元) + Exposure int64 `json:"exposure"` // 曝光量(次) + Click int64 `json:"click"` // 点击量(次) + Cpm float64 `json:"cpm"` // 单次曝光成本(处理时要转换成CPM方便理解,这字段定义真的一言难尽) + Cpc float64 `json:"cpc"` // 单次点击成本 + Ctr float64 `json:"ctr"` // 点击率 + Conversion int64 `json:"conversion"` // 浅层转化数 + ConversionSecond int64 `json:"conversion_second"` // 深层转化数 + Cvr float64 `json:"cvr"` // 浅层转化率 + CvrSecond float64 `json:"cvr_second"` // 深层转化率 + Og6 float64 `json:"og_6"` // 优化目标-关注 + Og7 float64 `json:"og_7"` // 优化目标-点击 + Og10 float64 `json:"og_10"` // 优化目标-跳转按钮点击 + Og105 float64 `json:"og_105"` // 优化目标- 注册(App) + Og106 int64 `json:"og_106"` // 优化目标-次日留存 + Og108 int64 `json:"og_108"` // 优化目标-完成购买数量 + Og112 int64 `json:"og_112"` // 优化目标-快应用加桌面 + Og114 int64 `json:"og_114"` // 优化目标-小游戏创角 + Og115 int64 `json:"og_115"` // 优化目标-游戏授权 + Og119 float64 `json:"og_119"` // 优化目标-授信 + Og120 int64 `json:"og_120"` // 优化目标-提现 + Og121 float64 `json:"og_121"` // 优化目标-广告变现 + Og202 int64 `json:"og_202"` // 优化目标-商品收藏 + Og204 float64 `json:"og_204"` // 优化目标-下单 + Og205 float64 `json:"og_205"` // 优化目标-付费 + Og301 float64 `json:"og_301"` // 优化目标-关键页面访问 + Og302 int64 `json:"og_302"` // 优化目标-H5注册 + Og307 int64 `json:"og_307"` // 优化目标-领券 + Og315 int64 `json:"og_315"` // 优化目标-浏览量 + Og316 int64 `json:"og_316"` // 优化目标-阅读文章 + Og318 int64 `json:"og_318"` // 优化目标-预授信 + Og403 int64 `json:"og_403"` // 优化目标-电话拨打 + Og405 float64 `json:"og_405"` // 优化目标-表单预约 + Og406 int64 `json:"og_406"` // 优化目标-完件 + Og409 float64 `json:"og_409"` // 优化目标-有效线索 + Og412 int64 `json:"og_412"` // 优化目标-加企微客户 + Og413 int64 `json:"og_413"` // 优化目标-选课 + Og418 int64 `json:"og_418"` // 优化目标-外链点击 + Og419 int64 `json:"og_419"` // 优化目标-购券 + Og421 int64 `json:"og_421"` // 优化目标-加群 + Og501 int64 `json:"og_501"` // 优化目标-打开公众号 + Og503 int64 `json:"og_503"` // 优化目标-关注后点击菜单栏 + Og10000 int64 `json:"og_10000"` // 优化目标-综合线索收集 + Og10004 int64 `json:"og_10004"` // 优化目标-首次购买会员 + Og10006 int64 `json:"og_10006"` // 优化目标-微信流量预约 + Og10007 int64 `json:"og_10007"` // 优化目标-首次下单 + Og10008 int64 `json:"og_10008"` // 优化目标-点赞 + Og10009 int64 `json:"og_10009"` // 优化目标-咨询留资 + Og10601 int64 `json:"og_10601"` // 优化目标-次留 + Og10801 float64 `json:"og_10801"` // 优化目标-首次付费 + Bo6 int64 `json:"bo_6"` // 推广目标-公众号关注数 + Bo7 int64 `json:"bo_7"` // 推广目标-公众号内下单人数 + Bo23 int64 `json:"bo_23"` // 推广目标-关键页面访问数 + Bo25 int64 `json:"bo_25"` // 推广目标-公众号注册数 + Bo26 int64 `json:"bo_26"` // 推广目标-公众号发消息数 + Bo41 int64 `json:"bo_41"` // 推广目标-公众号付费人数 + ConversionCost101 float64 `json:"101_conversion_cost"` // 下单单价 + Amount204 float64 `json:"204_amount"` // 下单金额 + Roi204 float64 `json:"204_roi"` // 下单ROI + Roi204fd float64 `json:"204_roi_fd"` // 首日下单ROI(T+1更新) + Roi204tw float64 `json:"204_roi_tw"` // 3日下单ROI + Roi204ow float64 `json:"204_roi_ow"` // 7日下单ROI + Roi204td float64 `json:"204_roi_td"` // 15日下单ROI + Roi204om float64 `json:"204_roi_om"` // 30日下单ROI + OrderCost float64 `json:"order_cost"` // 下单成本 + OrderCount int64 `json:"order_count"` // 下单数 + Roi float64 `json:"roi"` // ROI + MdMgPurchaseUv int64 `json:"md_mg_purchase_uv"` // 小游戏首次付费人数 + MdMgPurchaseVal1 int64 `json:"md_mg_purchase_val1"` // 小游戏首日付费金额(广告主回传)(分) + MdMgPurchaseVal int64 `json:"md_mg_purchase_val"` // 小游戏付费金额(分) + WeAppRegUv int64 `json:"weapp_reg_uv"` // 小游戏注册人数 + ActiveCount int64 `json:"active_count"` // 激活数 + InstallCount int64 `json:"install_count"` // 安装数 + Count107 int64 `json:"107_count"` // 加入购物车数 + AtCount402 int64 `json:"402_at_count"` // 开口数 + SendGoodsCount int64 `json:"send_goods_count"` // 发货数(次) + Sign int64 `json:"sign"` // 签收数(次) + AtRate409405 float64 `json:"409_405_at_rate"` // 表单有效率 + AtCost409 float64 `json:"409_at_cost"` // 有效销售线索成本 + AtCount409 int64 `json:"409_at_count"` // 有效销售线索数 + AtCost415 float64 `json:"415_at_cost"` // 试驾成本 + AtCount415 int64 `json:"415_at_count"` // 试驾数 + AtCost405 float64 `json:"405_at_cost"` // 表单预约成本(元) + AtCount405 int64 `json:"405_at_count"` // 表单预约数 + AtCost108 float64 `json:"108_at_cost"` // 完成购买成本(元) + AtCount108 int64 `json:"108_at_count"` // 完成购买数 + AogAction119 int64 `json:"119_aog_action"` // 授信数 + AogAction406 int64 `json:"406_aog_action"` // 完件数 + CvrClick119 float64 `json:"119_cvr_click"` // 点击授信率 + CvrClick406 float64 `json:"406_cvr_click"` // 点击完件率 + FinanceCreditPcvrAfterCaliBias float64 `json:"finance_credit_pcvr_after_cali_bias"` // pcvrbias金融pdcvr修正后授信(校正后) + FinanceCreditPcvrBeforeCaliBias float64 `json:"finance_credit_pcvr_before_cali_bias"` // pcvrbias金融pdcvr修正后授信(校正前) + FinanceApplyOrginalPcvrBias float64 `json:"finance_apply_original_pcvr_bias"` // 原始pcvrbias(金融pdcvr完件) + IndustryFinanceApplyPcvrBias float64 `json:"industry_finance_apply_pcvr_bias"` // pcvrbias(金融pdcvr完件) + ActiveCost float64 `json:"active_cost"` // 激活成本 + ActiveRegisterRate float64 `json:"active_register_rate"` // 激活注册率 + MdActiPurVal float64 `json:"md_acti_pur_val"` // 付费金额(激活口径) + MdActiPurValFdRoi float64 `json:"md_acti_pur_val_fd_roi"` // 首日付费金额(激活口径) + MdPurVal3 float64 `json:"md_pur_val_3"` // 3日付费金额(激活口径) + MdPurVal3Roi float64 `json:"md_pur_val_3_roi"` // 3日ROI(激活口径) + MdPurVal7 float64 `json:"md_pur_val_7"` // 7日付费金额(激活口径) + MdPurVal7Roi float64 `json:"md_pur_val_7_roi"` // 7日ROI(激活口径) + MdPurVal14 float64 `json:"md_pur_val_14"` // 14日付费金额(激活口径) + MdPurVal14Roi float64 `json:"md_pur_val_14_roi"` // 14日ROI(激活口径) + MdPurVal30 float64 `json:"md_pur_val_30"` // 30日付费金额(激活口径) + MdPurVal30Roi float64 `json:"md_pur_val_30_roi"` // 30日ROI(激活口径) +} +*/ + // ErrorCode 返回码 enum ErrorCode { SUCC = 0; // 成功 @@ -382,6 +531,8 @@ enum ErrorCode { CMD_ERROR = 202; // 命令行执行错误 API_ERROR = 301; // 调用内部API错误 + + TARGET_ERROR = 401; // Target参数错误 } enum CmdErrorCode { diff --git a/cmd/saastool/exp.go b/cmd/saastool/exp.go index 228ebae..1051695 100644 --- a/cmd/saastool/exp.go +++ b/cmd/saastool/exp.go @@ -35,7 +35,7 @@ Usage: saastoola exp COMMAND [OPTIONS] Commands: list List exps - get Get exp report + get Get exp report "help" is the default command. diff --git a/cmd/saastool/exp_get.go b/cmd/saastool/exp_get.go index 971a179..fec933b 100644 --- a/cmd/saastool/exp_get.go +++ b/cmd/saastool/exp_get.go @@ -1,5 +1,180 @@ package main +import ( + "flag" + "fmt" + "net/http" + "os" + "slices" + "strconv" + "strings" + + "git.algo.com.cn/public/saasapi" + "git.algo.com.cn/public/saasapi/pkg/saashttp" + "google.golang.org/protobuf/encoding/protojson" +) + +type getExpParams struct { + saasHttp *saashttp.SaasClient + expIDs []uint32 + beginDay uint64 + endDay uint64 + target string + advertiserIDs []uint64 + groupBy []string + totalFlag bool + extFields []string +} + func RunExpGet(args ...string) error { + fs := flag.NewFlagSet("get", flag.ExitOnError) + cfgFile := paramConfig(fs) + beginDay := paramWhereBeginDay(fs) + endDay := paramWhereEndDay(fs) + expIDs := paramWhereExpIds(fs) + target := paramWhereTarget(fs) + advertiserIDs := paramWhereAdvertiserId(fs) + groupBy := paramGroupBy(fs) + totalFlag := paramTotalFlag(fs) + extFields := paramExtFields(fs) + + if err := fs.Parse(args); err != nil { + fmt.Fprintln(os.Stderr, "command line parse error", "err", err) + return err + } + + if fs.NArg() > 0 { + fs.PrintDefaults() + return nil + } + + expIDsNumSlice := []uint32{} + if *expIDs != "" { + expIDsSlice := strings.Split(*expIDs, ",") + for _, id := range expIDsSlice { + idNum, err := strconv.ParseUint(id, 10, 32) + if err != nil { + fmt.Fprintln(os.Stderr, "expid parse error", "err", err) + return err + } + + if idNum == 0 || idNum > 10 { + fmt.Fprintln(os.Stderr, "expid range error") + return nil + } + expIDsNumSlice = append(expIDsNumSlice, uint32(idNum)) + } + } + + if *beginDay < 20250101 || *beginDay > 21001231 || *endDay < 20250101 || *endDay > 21001231 { + fmt.Fprintln(os.Stderr, "begin/end day error") + return nil + } + + if *target == "" { + fmt.Fprintln(os.Stderr, "target error") + return nil + } + + uidNumSlice := []uint64{} + if *advertiserIDs != "" { + uidSlice := strings.Split(*advertiserIDs, ",") + for _, id := range uidSlice { + idNum, err := strconv.ParseUint(id, 10, 64) + if err != nil { + fmt.Fprintln(os.Stderr, "advertiser id parse error", "err", err) + return err + } + + if idNum == 0 { + fmt.Fprintln(os.Stderr, "advertiser id error") + return nil + } + uidNumSlice = append(uidNumSlice, idNum) + } + } + + groupBySlice := []string{} + if *groupBy != "" { + validGroupBy := map[string]bool{"advertiser_id": true, "user_weight_factor": true} + groupBySlice := strings.Split(*groupBy, ",") + for _, group := range groupBySlice { + if !validGroupBy[group] { + fmt.Fprintln(os.Stderr, "group by error", "group", group) + return nil + } + } + } + + extFieldsSlice := []string{} + if *extFields != "" { + extFieldsSlice = strings.Split(*extFields, ",") + if slices.Contains(extFieldsSlice, "") { + fmt.Fprintln(os.Stderr, "ext field error") + return nil + } + } + + cfg, err := LoadConfigFile(*cfgFile) + if err != nil { + fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err) + return err + } + + getExpParams := getExpParams{ + saasHttp: &saashttp.SaasClient{ + Client: &http.Client{}, + ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls), + Auth: &cfg.Auth, + }, + expIDs: expIDsNumSlice, + beginDay: *beginDay, + endDay: *endDay, + target: *target, + advertiserIDs: uidNumSlice, + groupBy: groupBySlice, + totalFlag: *totalFlag, + extFields: extFieldsSlice, + } + return doExpGet(getExpParams) +} + +func doExpGet(getExpParams getExpParams) error { + + totalFlag := uint32(0) + if getExpParams.totalFlag { + totalFlag = 1 + } + + saasReq := &saasapi.SaasReq{ + Cmd: &saasapi.SaasReq_ExpGet{ + ExpGet: &saasapi.ExpGet{ + WhereExpId: getExpParams.expIDs, + WhereBeginDay: getExpParams.beginDay, + WhereEndDay: getExpParams.endDay, + WhereTarget: getExpParams.target, + WhereAdvertiserId: getExpParams.advertiserIDs, + GroupBy: getExpParams.groupBy, + TotalFlag: totalFlag, + ExtFields: getExpParams.extFields, + }, + }, + } + + res, err := getExpParams.saasHttp.ExpGet(saasReq) + + if err != nil { + fmt.Fprintln(os.Stderr, "submit GetExp error", "err", err) + return err + } + + if res.Code != saasapi.ErrorCode_SUCC { + fmt.Fprintln(os.Stderr, "get exp failed", "code", res.Code, "status", res.Status) + return nil + } + + getExpRes := res.GetExpGetRes() + + fmt.Printf("exp res: %v\n", protojson.Format(getExpRes)) return nil } diff --git a/cmd/saastool/params.go b/cmd/saastool/params.go index 7b936d8..5997a2b 100644 --- a/cmd/saastool/params.go +++ b/cmd/saastool/params.go @@ -117,6 +117,38 @@ func paramOS(fs *flag.FlagSet) *uint { return fs.Uint("os", 2, "1=iOS, 2=Android, default=2") } +func paramWhereBeginDay(fs *flag.FlagSet) *uint64 { + return fs.Uint64("beginday", 0, "Begin day") +} + +func paramWhereEndDay(fs *flag.FlagSet) *uint64 { + return fs.Uint64("endday", 0, "End day") +} + +func paramWhereExpIds(fs *flag.FlagSet) *string { + return fs.String("expids", "", "Exp IDs. Use commas to separate multiple IDs. empty is all") +} + +func paramWhereTarget(fs *flag.FlagSet) *string { + return fs.String("target", "", "Target ID") +} + +func paramWhereAdvertiserId(fs *flag.FlagSet) *string { + return fs.String("uid", "", "Advertiser IDs. Use commas to separate multiple IDs.") +} + +func paramGroupBy(fs *flag.FlagSet) *string { + return fs.String("groupby", "", "Group by. Use commas to separate multiple fields. empty is none") +} + +func paramExtFields(fs *flag.FlagSet) *string { + return fs.String("extfields", "", "Ext fields. Use commas to separate multiple fields. * is all") +} + +func paramTotalFlag(fs *flag.FlagSet) *bool { + return fs.Bool("total", false, "Total flag") +} + // ParseByteSize 解析字节大小字符串为字节数 func ParseByteSize(sizeStr string) (uint64, error) { sizeStr = strings.TrimSpace(sizeStr)