Compare commits

..

32 Commits

Author SHA1 Message Date
algotao
970d9db8da 修改测试数据集 2026-01-08 14:16:41 +08:00
algotao
d4bf3297d4 改良写入字段,减少使用者失误 2025-12-16 17:19:06 +08:00
algotao
9a892eb533 daemon模式写入序修正 2025-12-13 21:07:12 +08:00
algotao
765e75937d 实验报表授权、GEO支持 2025-12-13 09:16:21 +08:00
algotao
cbbeb04ee5 更新docker版本 2025-11-23 12:05:58 +08:00
algotao
c9d794430e 调整授权功能 2025-11-23 12:01:33 +08:00
algotao
4575590faa 增加grant的ds字段 2025-11-19 12:32:36 +08:00
algotao
25715910cb 调整lua proto编号 2025-11-16 16:10:43 +08:00
algotao
430ce87959 支持数据授权管理功能 2025-11-14 19:24:18 +08:00
algotao
85f64c16b4 修正help文本 2025-11-14 16:52:36 +08:00
algotao
00fb793d9a 支持策略创建、删除,脚本列表、创建、删除、获取、使用 2025-11-10 15:57:31 +08:00
algotao
f9b7857b24 修改输出格式 2025-11-05 17:27:23 +08:00
algotao
c430544562 修改编译镜像引用 2025-11-05 11:35:01 +08:00
e48a840959 修正 2025-11-04 21:25:50 +08:00
algotao
2bf848f79b 改字 2025-11-03 10:21:20 +08:00
4008b44a77 支持鸿蒙系统 2025-10-21 16:29:01 +08:00
a8a54cc1bc 修正groupby字段读取逻辑 2025-10-18 15:11:50 +08:00
0230085a70 优化proto字段名称 2025-10-16 12:44:37 +08:00
df62e4fae6 支持实验数据拉取 2025-10-16 10:09:20 +08:00
algotao
d7ab7b5156 saastool增加docker/daemon模式 2025-09-24 18:38:03 +08:00
algotao
a88c5c6e3f 展示存储版本 2025-09-16 18:53:54 +08:00
algotao
ca81fba208 支持显示运行进度 2025-09-16 10:49:54 +08:00
algotao
fade72885f 去除u8区的高区操作功能 2025-09-09 11:03:25 +08:00
algotao
fff023b56d 增加lua调试功能 2025-09-02 15:45:56 +08:00
algotao
ed06c46bde 更换包域名 2025-08-30 15:59:39 +08:00
algotao
095a0b9b01 更新 2025-08-30 14:22:05 +08:00
algotao
80a758f1e3 增加info获取接口 2025-08-09 22:09:10 +08:00
algotao
edb12c3b1f 增加策略列表、绑定、解绑 2025-08-09 15:54:57 +08:00
algotao
6ca9fe7a02 增加任务取回功能 2025-07-27 18:16:08 +08:00
algotao
a78c16d301 优化task make 2025-07-25 17:25:17 +08:00
algotao
a2bf3c853e 为task增加sourcepath,便于处理 2025-07-25 12:04:16 +08:00
algotao
d1ad148725 兼容单文件处理 2025-06-07 19:15:23 +08:00
62 changed files with 7718 additions and 358 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,5 @@
vendor/
*.out
build/
*.lua
*.bak

12
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,12 @@
{
"go.useLanguageServer": true,
"[go]": {
"editor.insertSpaces": true,
"editor.tabSize": 4,
"editor.indentSize": 4
},
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
}

4094
cmd.pb.go

File diff suppressed because it is too large Load Diff

402
cmd.proto
View File

@@ -2,11 +2,13 @@ syntax = "proto3";
package saasapi;
option go_package = "e.coding.net/rta/public/saasapi";
option go_package = "git.algo.com.cn/public/saasapi";
// SaasReq 命令请求
message SaasReq {
oneof cmd {
Info info = 5; // 获取账号设置
Read read = 10; // 批量读取
Write write = 11; // 批量写入
ColumnWrite column_write = 12; // 全量列式写入
@@ -16,9 +18,38 @@ message SaasReq {
TaskRun task_run = 22; // 执行任务
TaskDelete task_delete = 23; // 删除任务
TaskInfo task_info = 24; // 任务详情
TargetList target_list = 50; // 列出策略及绑定
TargetCreate target_create = 51; // 创建策略
TargetDelete target_delete = 52; // 删除策略
BindSet bind_set = 61; // 设置绑定
BindDelete bind_delete = 62; // 解除绑定
GrantList grant_list = 70; // 列出数据授权
Grant grant_add = 71; // 增加数据授权
Grant grant_delete = 72; // 删除数据授权
ScriptRun script_run = 90; // 运行脚本
ScriptCreate script_create = 91; // 脚本创建
ScriptList script_list = 92; // 列出脚本
ScriptDelete script_delete = 93; // 删除脚本
ScriptGet script_get = 94; // 获取脚本内容
ScriptUse script_use = 95; // 使用脚本
ExpList exp_list = 100; // 列出实验
ExpGet exp_get = 101; // 获取实验报表
ExpGrantList exp_grant_list = 102; // 列出访问实验报表授权
ExpGrant exp_grant_add = 103; // 授权他人访问实验报表
ExpGrant exp_grant_delete = 104; // 取消他人访问实验报表
}
}
// Info 获取账号信息
message Info {
}
// Read 批量读取命令
message Read {
string dataspace_id = 1; // 数据空间ID
@@ -42,29 +73,30 @@ message Write {
// WriteItem 写入命令
message WriteItem {
string userid = 1; // 用户ID
Bytes write_bytes = 2; // byte区域
Uint32s write_uint32s = 3; // uint32区域
FlagsWithExpire write_flags_with_expire = 4; // 标志位区域
Bytes write_bytes = 2 [deprecated = true]; // byte区域。!!!弃用请使用bytes_kv
Uint32s write_uint32s = 3 [deprecated = true]; // uint32区域。!!!弃用请使用uint32s_kv
FlagsWithExpire write_flags_with_expire = 4 [deprecated = true]; // 标志位区域。!!!弃用请使用flags_with_expire_kv
map<uint32, uint32> bytes_kv = 5; // 写入bytekey为1-64索引值value为0-255数值。index/value超限会丢弃
map<uint32, uint32> uint32s_kv = 6; // 写入uint32key为1-8索引值value为uint32数值。index超限会丢弃
map<uint32, FlagWithExpire> flags_with_expire_kv = 7; // 写入标志位key为1-4索引值index超限会丢弃
}
// Bytes 写入byte区域
message Bytes {
bytes bytes = 1; // 写入的byte
uint64 index_1 = 2; // 写入byte的索引值(0..63)
uint64 index_2 = 3; // 写入byte的索引值(64..127)
}
// Uint32s 写入uint32区域
message Uint32s {
repeated uint32 uint32s = 1; // 写入的uint32
uint64 index_1 = 2; // 写入uint32的索引值(0..15) 最多 16
//uint64 index_2 = 3; // 写入uint32的索引值(当前不支持)
uint64 index_1 = 2; // 写入uint32的索引值(0..7) 最多 8
}
// FlagsWithExpire 写入标志位区域
message FlagsWithExpire {
repeated FlagWithExpire flags_with_expire = 1; // 写入的标志位
uint64 index_1 = 2; // 写入标志位的索引值
uint64 index_1 = 2; // 写入标志位的索引值(0..3) 最多 4 个
}
// FlagWithExpire 标志位
@@ -89,12 +121,16 @@ message Task {
string task_sha256 = 3; // 任务sha256
string task_description = 4; // 任务描述
repeated FileInfo task_file_infos = 5; // 文件列表
uint64 task_block_size = 6; // 文件块字节大小(推荐200M
uint64 task_block_size = 6; // 文件块字节大小(推荐50M
string source_path = 7; // 任务数据源路径
uint64 task_size = 8; // 任务所有文件的总大小
// 以下字段只在返回时填写,用于提供服务端的任务状态。在请求时填写会被忽略
string create_time = 10; // 创建时间
string run_time = 11; // 运行时间
string finish_time = 12; // 完成时间
uint32 running_block = 13; // 正在运行的块编号
uint32 total_block = 14; // 总块数
TaskStatus status = 15; // 任务状态
}
@@ -119,23 +155,132 @@ message TaskInfo {
string task_sha256 = 1; // 任务sha256
}
// FileInfo 任务文件信息
message FileInfo {
string file_name = 1; // 文件名
uint64 file_size = 2; // 文件大小
repeated FileBlock file_blocks = 3; // 文件块列表
}
// FileBlock 文件块信息
message FileBlock {
string block_sha256 = 1; // 块的sha256
uint64 block_length = 2; // 块的字节长度
bool uploaded = 3; // 是否已上传在TaskCreate/TaskInfo请求返回
}
// TargetList 列出策略
message TargetList {
repeated string targets = 1; // 指定要列出的绑定的策略列表,如不指定则返回全部
bool list_bind = 2; // 是否同时列出绑定信息
}
// TargetCreate 创建策略
message TargetCreate {
string target_id = 1; // 策略ID
string target_description = 2; // 策略描述
}
// TargetDelete 删除策略
message TargetDelete {
string target_id = 1; // 策略ID
}
// BindSet 设置绑定
message BindSet {
repeated Bind binds = 2; // 设置绑定内容
}
// BindDelete 删除绑定
message BindDelete {
repeated Bind binds = 2; // 解除绑定内容
}
// GrantList 列出数据授权
message GrantList {
}
// Grant 数据授权信息
message Grant {
uint32 target_account_id = 1; // sRTA授权目标账号ID
string grant_index = 2; // 授权索引。格式为 "index1, index2, index55-index64",例如 "1, 2, 55-64"
uint32 dataspace_id = 3; // 授权数据空间ID数字型
}
// ScriptRun 运行脚本
message ScriptRun {
string lua_script = 1; // 要调试的lua脚本
string server_did = 2; // 将从服务端读取该DID下的数据
string appid = 3; // 小程序/小游戏/公众号/视频号的appid
string server_openid = 4; // 将从服务端读取该openid下的数据需与appid配对使用
OS os = 5; // 操作系统
}
// ScriptCreate 创建脚本
message ScriptCreate {
string lua_name = 1; // 要上传的脚本名称
string lua_script = 2; // 要调试的lua脚本
}
// ScriptList 列出脚本
message ScriptList {
}
// ScriptDelete 删除脚本
message ScriptDelete {
string lua_name = 1; // 要删除的脚本名称
}
// ScriptGet 获取脚本
message ScriptGet {
string lua_name = 1; // 要获取的脚本名称
}
// ScriptUse 使用脚本
message ScriptUse {
string lua_name = 1; // 要使用的脚本名称
}
// ExpList 列出实验
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_bucket_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 total_flag = 30; // 是否汇总0=不汇总1=汇总
}
message ExpGrantList {
}
message ExpGrant {
uint32 target_account_id = 1; // sRTA授权目标账号ID
}
// SaasRes 命令返回
message SaasRes {
ErrorCode code = 1; // 返回码
string status = 2; // 返回信息的文本提示
oneof res {
InfoRes info_res = 5; // 账号信息返回
ReadRes read_res = 10; // 读取命令返回
WriteRes write_res = 11; // 写入命令返回
@@ -144,18 +289,57 @@ message SaasRes {
Task task_run_res = 22; // 运行任务返回状态
Task task_delete_res = 23; // 删除任务返回状态
Task task_info_res = 24; // 任务详情返回状态
TargetListRes target_list_res = 50; // 列出策略及绑定返回状态
TargetCreateRes target_create_res = 51; // 创建策略返回状态
TargetDeleteRes target_delete_res = 52; // 删除策略返回状态
BindSetRes bind_set_res = 61; // 设置绑定返回状态
BindDeleteRes bind_delete_res = 62; // 删除绑定返回状态
GrantListRes grant_list_res = 70; // 列出数据授权返回状态
Grant grant_add_res = 71; // 增加数据授权返回状态
Grant grant_delete_res = 72; // 删除数据授权返回状态
ScriptRunRes script_run_res = 90; // 运行脚本返回
ScriptCreateRes script_create_res = 91; // 创建脚本返回
ScriptListRes script_list_res = 92; // 列出脚本返回
ScriptDeleteRes script_delete_res = 93; // 删除脚本返回
ScriptGetRes script_get_res = 94; // 获取脚本返回
ScriptUseRes script_use_res = 95; // 使用脚本返回
ExpListRes exp_list_res = 100; // 实验列表返回
ExpGetRes exp_get_res = 101; // 实验报表返回
ExpGrantListRes exp_grant_list_res = 102; // 实验授权列表返回
ExpGrant exp_grant_add_res = 103; // 增加实验授权返回
ExpGrant exp_grant_delete_res = 104; // 实验解除授权返回
}
}
message DataSpace {
repeated string did = 1; // 设备ID区
repeated string wuid = 2; // OpenID区
repeated string geo = 7; // GEO区
}
// InfoRes 账号信息返回
message InfoRes {
DataSpace dataspace = 1; // 可用数据区列表
repeated string target_id = 2; // 策略ID列表
}
// ReadRes 读记录返回
message ReadRes {
uint32 succ_cmd_count = 1; // 成功的命令数量
uint32 fail_cmd_count = 2; // 失败的命令数量
repeated ValueItem cmd_res = 3; // 返回的命令
repeated ValueItem cmd_res = 3 ; // 返回的命令
}
// WriteRes 写记录返回
message WriteRes {
//uint32 succ_cmd_count = 1; // 成功的命令数量
//uint32 fail_cmd_count = 2; // 失败的命令数量
//uint32 succ_cmd_count = 1; // 成功的命令数量
//uint32 fail_cmd_count = 2; // 失败的命令数量
repeated string failed_userid = 3; // 返回的失败的用户ID
}
@@ -163,23 +347,188 @@ message WriteRes {
message ValueItem {
uint32 cmd_index = 1; // 命令索引
CmdErrorCode cmd_code = 2; // 状态
bytes bytes = 3; // byte区域
repeated uint32 uint32s = 4; // uint32区域
repeated FlagWithExpire flags_with_expire = 5; // 标志位区域
bytes bytes = 3 [deprecated = true]; // byte区域。!!!弃用
repeated uint32 uint32s = 4 [deprecated = true]; // uint32区域。!!!弃用
repeated FlagWithExpire flags_with_expire = 5 [deprecated = true]; // 标志位区域。!!!弃用
uint32 last_modify_time = 6; // 最后修改时间
uint32 version = 7; // 存储版本
map<uint32, uint32> bytes_kv = 8; // byte区域
map<uint32, uint32> uint32s_kv = 9; // uint32区域
map<uint32, FlagWithExpire> flags_with_expire_kv = 10; // 标志位区域
}
// TaskListRes 任务列表返回
message TaskListRes {
repeated Task tasks = 1; // 任务列表
}
// TargetListRes 策略列表返回
message TargetListRes {
map<string, Binds> target_list = 1; // 绑定列表
}
// TargetCreateRes 策略创建返回
message TargetCreateRes {
string target_id = 1; // 策略ID
string target_description = 2; // 策略描述
}
// TargetDeleteRes 策略创建返回
message TargetDeleteRes {
string target_id = 1; // 策略ID
string target_description = 2; // 策略描述
}
message Binds {
repeated Bind binds = 1; // 绑定列表
}
// 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; // 绑定操作来源
}
// BindType 绑定类型
enum BindType {
UnknownBindType = 0;
AdgroupId = 1; // 广告
AccountId = 3; // 广告主
}
// BindSourceType 绑定操作来源
enum BindSourceType {
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; // 绑定错误的记录
}
// BindDeleteRes 删除绑定返回
message BindDeleteRes {
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; // 错误绑定原因
}
// GrantListRes 授权列表返回
message GrantListRes {
repeated Grant from = 1; // 被授权列表
repeated Grant to = 2; // 向外授权列表
}
// ScriptRunRes 运行脚本返回
message ScriptRunRes {
string print_output = 1; // print输出
string error_output = 2; // 错误信息
string targets_output = 3; // 策略输出
string dataspace_out = 4; // 数据区输出
}
message ScriptInfo {
string lua_name = 1; // 脚本名称
string lua_script = 2; // 脚本内容
bool lua_checked = 3; // 脚本校验结果
bool lua_used = 4; // 脚本是否被使用
}
// ScriptCreateRes 创建脚本返回
message ScriptCreateRes {
ScriptInfo script_info = 1; // 脚本信息
}
// ScriptListRes 脚本列表返回
message ScriptListRes {
repeated ScriptInfo script_info = 1; // 脚本信息
}
// ScriptGetRes 获取脚本返回
message ScriptGetRes {
ScriptInfo script_info = 1; // 脚本信息
}
// ScriptDeleteRes 删除脚本返回
message ScriptDeleteRes {
ScriptInfo script_info = 1; // 脚本信息
}
// ScriptUseRes 使用脚本返回
message ScriptUseRes {
ScriptInfo script_info = 1; // 脚本信息
}
// ExpListRes 实验列表返回
message ExpListRes {
repeated ExpBucket buckets = 1; // 实验桶
}
message ExpBucket {
uint32 bucket_id = 1; // 分桶号
uint32 pt_exp_id = 2; // 平台实验ID
uint32 percent = 3; // 流量百分比
}
// ExpGetRes 实验报表返回
message ExpGetRes {
repeated ExpData exp_data = 1; // 实验数据
}
// ExpData 实验数据
message ExpData {
uint64 time = 1; // 日期
uint32 bucket_id = 2; // 分桶ID
ExpBaseFields base_fields = 3; // 基础字段
map <string, double> ext_fields = 4; // 扩展字段
map<string, uint64> group = 5; // 分组
}
// ExpBaseFields 基础实验字段
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; // 深层转化量
}
// ExpGrantListRes 授权列表返回
message ExpGrantListRes {
repeated ExpGrant from = 1; // 被授权列表
repeated ExpGrant to = 2; // 向外授权列表
}
// ErrorCode 返回码
enum ErrorCode {
SUCC = 0; // 成功
INVALID_ACCOUNT = 101; // Account不合法
INVALID_TIMESTAMP = 102; // 头信息缺少时间戳或不正确
INVALID_SIGNATURE = 103; // 头信息缺少签名
AUTH_FAIL = 104; // 签名验失败
AUTH_FAIL = 104; // 签名验失败
DISABLED_ACCOUNT = 105; // 账号已禁用
INVALID_CONTENT_TYPE = 110; // 非法的Content-Type
READ_BODY = 111; // 读取 http body 失败
@@ -204,12 +553,17 @@ enum ErrorCode {
DATA_ERROR = 201; // 数据错误
CMD_ERROR = 202; // 命令行执行错误
API_ERROR = 301; // 调用内部API错误
PARAM_ERROR = 401; // 参数错误
}
enum CmdErrorCode {
OK = 0; // 成功
}
// TaskStatus 任务状态
enum TaskStatus {
ALL = 0; // 全部
WAITING = 1; // 等待中
@@ -218,6 +572,20 @@ enum TaskStatus {
SUCCESS = 4; // 成功
FAIL = 5; // 失败
DELETED = 10; // 已删除,仅在执行删除成功时返回
DELETED = 10; // 已删除,仅在执行删除成功时返回
}
enum OS {
OS_UNKNOWN = 0;
IOS = 1;
ANDROID = 2;
HARMONY = 7; //纯血鸿蒙
}
// MAX 最大限定
enum MAX {
MAX_UNKNOWN = 0;
U8 = 64;
U32 = 8;
FLAG = 4;
}

View File

@@ -1,4 +1,7 @@
debug/
saastool
saastool_linux
cfg.toml
*.toml
test/
*.lua
test.txt

46
cmd/saastool/bind.go Normal file
View File

@@ -0,0 +1,46 @@
package main
import (
"fmt"
"os"
"strings"
)
func RunBind(args ...string) error {
name, args := ParseCommandName(args)
// 从参数中解析出命令
switch name {
case "", "help":
return RunBindHelp(args...)
case "setaccount":
return RunBindSetAccount(args...)
case "setad":
return RunBindSetAd(args...)
case "delete":
return RunBindDelete(args...)
default:
err := fmt.Errorf(`unknown command "%s"`+"\n"+`Run 'saastool bind help' for usage`, name)
fmt.Fprintln(os.Stderr, err)
return err
}
}
func RunBindHelp(args ...string) error {
fmt.Println(strings.TrimSpace(bindUsage))
return nil
}
const bindUsage = `
Usage: saastoola bind COMMAND [OPTIONS]
Commands:
setaccount Set Account binds
setad Set AdGroup binds
delete Delete binds
"help" is the default command.
Use "saastool bind COMMAND -help" for more information about a command.
`

105
cmd/saastool/bind_delete.go Normal file
View File

@@ -0,0 +1,105 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"strconv"
"strings"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type bindDeleteParams struct {
idType int
ids []int64
saasHttp *saashttp.SaasClient
}
func RunBindDelete(args ...string) error {
fs := flag.NewFlagSet("delete", flag.ExitOnError)
cfgFile := paramConfig(fs)
idtype := paramIdType(fs)
ids := paramIDs(fs)
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err)
return err
}
// 切割字符串
idsSlice := strings.Split(*ids, ",")
if len(idsSlice) == 1 && idsSlice[0] == "" {
idsSlice = []string{}
}
if fs.NArg() > 0 || len(idsSlice) == 0 || (len(idsSlice) == 1 && idsSlice[0] == "") {
fs.PrintDefaults()
return nil
}
numIds := []int64{}
for _, v := range idsSlice {
n, err := strconv.ParseInt(v, 10, 64)
if err != nil {
fmt.Fprintln(os.Stderr, "id parse error", "value", v, "err", err)
return err
}
numIds = append(numIds, n)
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
bindDeleteParams := bindDeleteParams{
idType: *idtype,
ids: numIds,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doBindDeleteAccount(bindDeleteParams)
}
func doBindDeleteAccount(p bindDeleteParams) error {
bindDelete := &saasapi.BindDelete{}
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_BindDelete{
BindDelete: bindDelete,
},
}
for _, v := range p.ids {
bindDelete.Binds = append(bindDelete.Binds, &saasapi.Bind{
BindId: v,
BindType: saasapi.BindType(p.idType),
})
}
res, err := p.saasHttp.BindDelete(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Bind Delete error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "Bind Delete failed", "code", res.Code, "status", res.Status)
return nil
}
bindRes := res.GetBindDeleteRes()
fmt.Printf("bind res: %v\n", protojson.Format(bindRes))
return nil
}

View File

@@ -0,0 +1,105 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"strconv"
"strings"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type bindSetAccountParams struct {
target string
accounts []int64
saasHttp *saashttp.SaasClient
}
func RunBindSetAccount(args ...string) error {
fs := flag.NewFlagSet("setaccount", flag.ExitOnError)
cfgFile := paramConfig(fs)
target := paramTarget(fs)
accounts := paramAccounts(fs)
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err)
return err
}
// 切割字符串
idsSlice := strings.Split(*accounts, ",")
if len(idsSlice) == 1 && idsSlice[0] == "" {
idsSlice = []string{}
}
if fs.NArg() > 0 || len(idsSlice) == 0 || (len(idsSlice) == 1 && idsSlice[0] == "") {
fs.PrintDefaults()
return nil
}
numAccounts := []int64{}
for _, v := range idsSlice {
n, err := strconv.ParseInt(v, 10, 64)
if err != nil {
fmt.Fprintln(os.Stderr, "account parse error", "value", v, "err", err)
return err
}
numAccounts = append(numAccounts, n)
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
bindSetAccountParams := bindSetAccountParams{
target: *target,
accounts: numAccounts,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doBindSetAccount(bindSetAccountParams)
}
func doBindSetAccount(p bindSetAccountParams) error {
bindSet := &saasapi.BindSet{}
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_BindSet{
BindSet: bindSet,
},
}
for _, v := range p.accounts {
bindSet.Binds = append(bindSet.Binds, &saasapi.Bind{
BindId: v,
BindType: saasapi.BindType_AccountId,
TargetId: p.target,
AccountId: v,
})
}
res, err := p.saasHttp.BindSet(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Bind Set error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "Bind Set failed", "code", res.Code, "status", res.Status)
return nil
}
fmt.Printf("bind res: %v\n", protojson.Format(res.GetBindSetRes()))
return nil
}

108
cmd/saastool/bind_setad.go Normal file
View File

@@ -0,0 +1,108 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"strconv"
"strings"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type bindSetAdParams struct {
target string
account int64
ads []int64
saasHttp *saashttp.SaasClient
}
func RunBindSetAd(args ...string) error {
fs := flag.NewFlagSet("setad", flag.ExitOnError)
cfgFile := paramConfig(fs)
target := paramTarget(fs)
account := paramAccount(fs)
ads := paramAds(fs)
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err)
return err
}
// 切割字符串
idsSlice := strings.Split(*ads, ",")
if len(idsSlice) == 1 && idsSlice[0] == "" {
idsSlice = []string{}
}
if fs.NArg() > 0 || len(idsSlice) == 0 || (len(idsSlice) == 1 && idsSlice[0] == "") {
fs.PrintDefaults()
return nil
}
numAds := []int64{}
for _, v := range idsSlice {
n, err := strconv.ParseInt(v, 10, 64)
if err != nil {
fmt.Fprintln(os.Stderr, "account parse error", "value", v, "err", err)
return err
}
numAds = append(numAds, n)
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
bindSetAdParams := bindSetAdParams{
target: *target,
account: *account,
ads: numAds,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doBindSetAd(bindSetAdParams)
}
func doBindSetAd(p bindSetAdParams) error {
bindSet := &saasapi.BindSet{}
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_BindSet{
BindSet: bindSet,
},
}
for _, v := range p.ads {
bindSet.Binds = append(bindSet.Binds, &saasapi.Bind{
BindId: v,
BindType: saasapi.BindType_AdgroupId,
TargetId: p.target,
AccountId: p.account,
})
}
res, err := p.saasHttp.BindSet(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Bind Set error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "Bind Set failed", "code", res.Code, "status", res.Status)
return nil
}
fmt.Printf("bind res: %v\n", protojson.Format(res.GetBindSetRes()))
return nil
}

View File

@@ -1,7 +1,7 @@
package main
import (
"e.coding.net/rta/public/saasapi/pkg/saashttp"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"github.com/BurntSushi/toml"
)

View File

@@ -11,7 +11,7 @@ import (
"strings"
"sync"
"e.coding.net/rta/public/saasapi"
"git.algo.com.cn/public/saasapi"
"google.golang.org/protobuf/encoding/protojson"
)
@@ -236,11 +236,7 @@ func convertBatch(lines []string, convertParams convertParams, resultChan chan<-
saasWriteItem.WriteBytes = &saasapi.Bytes{}
}
saasWriteItem.WriteBytes.Bytes = append(saasWriteItem.WriteBytes.Bytes, *targetinfo.WriteByte)
if targetinfo.WriteBytePos < 64 {
saasWriteItem.WriteBytes.Index_1 |= 1 << targetinfo.WriteBytePos
} else if targetinfo.WriteBytePos < 128 {
saasWriteItem.WriteBytes.Index_2 |= 1 << (targetinfo.WriteBytePos - 64)
}
saasWriteItem.WriteBytes.Index_1 |= 1 << targetinfo.WriteBytePos
}
if targetinfo.WriteUint32 != nil {

View File

@@ -0,0 +1,61 @@
package main
import (
"encoding/json"
"fmt"
"os"
"git.algo.com.cn/public/saasapi"
)
// MapConfig 配置
type MapConfig struct {
Targets map[string]*Target `json:"targets"`
}
// Target 配置
type Target struct {
WriteByte *byte `json:"write_byte"` // byte值
WriteBytePos uint32 `json:"write_byte_pos"` // byte写入位置
WriteUint32 *uint32 `json:"write_uint32"` // uint32值
WriteUint32Pos uint32 `json:"write_uint32_pos"` // uint32写入位置
WriteFlag *bool `json:"write_flag"` // 标志位
WriteExpire *uint32 `json:"write_expire"` // 过期时间
WriteFlagWithExpirePos uint32 `json:"write_flag_with_expire_pos"` // 标志与过期写入位置
}
// LoadConfigFile 加载配置文件
func LoadMapFile(filename string) (*MapConfig, error) {
// 打开文件
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
sc := &MapConfig{}
err = json.NewDecoder(f).Decode(sc)
if err != nil {
return nil, err
}
for targetName, targetInfo := range sc.Targets {
if targetInfo.WriteBytePos >= uint32(saasapi.MAX_U8) {
err = fmt.Errorf("%v WriteBytePos>MAX_U8 , current %v, MAX %v", targetName, targetInfo.WriteBytePos, uint32(saasapi.MAX_U8)-1)
break
}
if targetInfo.WriteUint32Pos >= uint32(saasapi.MAX_U32) {
err = fmt.Errorf("%v WriteUint32Pos>MAX_U32 , current %v, MAX %v", targetName, targetInfo.WriteUint32Pos, uint32(saasapi.MAX_U32)-1)
break
}
if targetInfo.WriteFlagWithExpirePos >= uint32(saasapi.MAX_FLAG) {
err = fmt.Errorf("%v WriteFlagWithExpirePos>MAX_FLAG , current %v, MAX %v", targetName, targetInfo.WriteFlagWithExpirePos, uint32(saasapi.MAX_FLAG)-1)
break
}
}
return sc, err
}

378
cmd/saastool/daemon.go Normal file
View File

@@ -0,0 +1,378 @@
package main
import (
"bufio"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
)
type Daemon struct {
saasHttp *saashttp.SaasClient
currTimeStamp uint32
}
type daemonPublicParams struct {
ds string
appid string
}
func RunDaemon(args ...string) error {
var err error
account := os.Getenv("SRTA_ACCOUNT")
token := os.Getenv("SRTA_TOKEN")
env := os.Getenv("SRTA_ENV")
slog.Info("Env", "SRTA_ACCOUNT", account)
slog.Info("Env", "SRTA_TOKEN", token)
slog.Info("Env", "SRTA_ENV", env)
if strings.TrimSpace(account) == "" {
err = fmt.Errorf("SRTA_ACCOUNT is empty")
slog.Error("Env", "err", err)
return err
}
if strings.TrimSpace(token) == "" {
err = fmt.Errorf("SRTA_TOKEN is empty")
slog.Error("Env", "err", err)
return err
}
apiurls := &saashttp.ApiUrls{}
switch strings.ToLower(env) {
case "demo":
apiurls.BaseUrl = "https://srta.algo.com.cn"
case "prd":
apiurls.BaseUrl = "https://api.rta.qq.com"
case "dev":
apiurls.BaseUrl = "http://localhost:8080"
default:
err = fmt.Errorf("SRTA_ENV is not demo or prd")
slog.Error("Env", "err", err)
return err
}
mux := http.NewServeMux()
daemon := &Daemon{
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(apiurls),
Auth: &saashttp.Auth{
Account: account,
Token: token,
},
},
}
mux.HandleFunc("/read", daemon.httpRead)
mux.HandleFunc("/write", daemon.httpWrite)
daemonPort := os.Getenv("SRTA_PORT")
if strings.TrimSpace(daemonPort) == "" {
daemonPort = "8080"
}
daemonPort = ":" + daemonPort
svrHttp := http.Server{
Addr: daemonPort,
Handler: mux,
}
slog.Info("Start running", "port", daemonPort)
err = svrHttp.ListenAndServe()
if err != nil {
slog.Error("failed", "err", err)
return err
}
return nil
}
func (d *Daemon) httpRead(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
w.Header().Set("Allow", http.MethodGet)
http.Error(w, fmt.Sprintf("Not support method: %s。Only GET。", r.Method), http.StatusMethodNotAllowed)
return
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("X-Content-Type-Options", "nosniff")
saasRes := &saasapi.SaasRes{}
defer func() {
json.NewEncoder(w).Encode(saasRes)
}()
params, err := d.parsePublicParams(r)
if err != nil {
saasRes.Code = saasapi.ErrorCode_CMD_ERROR
saasRes.Status = err.Error()
return
}
q := r.URL.Query()
userid := strings.TrimSpace(q.Get("userid"))
if len(userid) == 0 {
saasRes.Code = saasapi.ErrorCode_CMD_ERROR
saasRes.Status = "userid is null"
return
}
saasReadItems := []*saasapi.ReadItem{}
saasReadItems = append(saasReadItems, &saasapi.ReadItem{
Userid: userid,
})
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_Read{
Read: &saasapi.Read{
DataspaceId: params.ds,
Appid: params.appid,
ReadItems: saasReadItems,
},
},
}
saasRes, err = d.saasHttp.Read(saasReq)
if err != nil {
saasRes.Code = saasapi.ErrorCode_CMD_ERROR
saasRes.Status = fmt.Sprintf("submit read error. %v", err)
return
}
}
func (d *Daemon) httpWrite(w http.ResponseWriter, r *http.Request) {
bPost := false
switch r.Method {
case http.MethodPost:
bPost = true
case http.MethodGet:
default:
w.Header().Set("Allow", http.MethodGet)
http.Error(w, fmt.Sprintf("Not support method: %s。Only GET/POST。", r.Method), http.StatusMethodNotAllowed)
return
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("X-Content-Type-Options", "nosniff")
saasRes := &saasapi.SaasRes{}
defer func() {
json.NewEncoder(w).Encode(saasRes)
}()
params, err := d.parsePublicParams(r)
if err != nil {
saasRes.Code = saasapi.ErrorCode_CMD_ERROR
saasRes.Status = err.Error()
return
}
q := r.URL.Query()
clear := q.Get("clear")
bClear := false
if len(clear) > 0 {
bClear, err = strconv.ParseBool(clear)
if err != nil {
saasRes.Code = saasapi.ErrorCode_CMD_ERROR
saasRes.Status = fmt.Sprintf("clear is error. %v", err)
return
}
}
d.currTimeStamp = uint32(time.Now().Unix())
writeItems, err := d.parseWriteParams(r, bPost)
if err != nil {
saasRes.Code = saasapi.ErrorCode_CMD_ERROR
saasRes.Status = fmt.Sprintf("write info error. %v", err)
return
}
write := &saasapi.Write{
DataspaceId: params.ds,
Appid: params.appid,
IsClearAllFirst: bClear,
}
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_Write{
Write: write,
},
}
write.WriteItems = writeItems
saasRes, err = d.saasHttp.Write(saasReq)
if err != nil {
saasRes.Code = saasapi.ErrorCode_CMD_ERROR
saasRes.Status = fmt.Sprintf("submit write error. %v", err)
return
}
}
func (d *Daemon) parsePublicParams(r *http.Request) (*daemonPublicParams, error) {
params := &daemonPublicParams{}
q := r.URL.Query()
params.ds = strings.ToLower(strings.TrimSpace(q.Get("ds")))
switch params.ds {
case "did", "wuid", "geo":
default:
return nil, fmt.Errorf("ds must use did/wuid/geo. current is %v", params.ds)
}
params.appid = strings.TrimSpace(q.Get("appid"))
if params.ds == "wuid" && len(params.appid) == 0 {
return nil, fmt.Errorf("appid must exist when ds=wuid")
}
return params, nil
}
func (d *Daemon) parseWriteParams(r *http.Request, post bool) (writeItems []*saasapi.WriteItem, reterr error) {
writeItems = nil
lineNum := 0
if post {
scanner := bufio.NewScanner(r.Body)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
lineNum++
parsedQuery, err := url.ParseQuery(line)
if err != nil {
reterr = fmt.Errorf("parse error: %v", err)
return
}
item, err := d.parseQuery(parsedQuery, lineNum)
if err != nil {
reterr = fmt.Errorf("parse error: %v", err)
return
}
writeItems = append(writeItems, item)
}
} else {
item, err := d.parseQuery(r.URL.Query(), lineNum)
if err != nil {
reterr = fmt.Errorf("parse error: %v", err)
return
}
writeItems = append(writeItems, item)
}
return
}
func (d *Daemon) parseQuery(q url.Values, lineNum int) (writeItem *saasapi.WriteItem, reterr error) {
userid := strings.TrimSpace(q.Get("userid"))
if len(userid) == 0 {
reterr = fmt.Errorf("userid is null. line %v", lineNum)
return
}
writeItem = &saasapi.WriteItem{
Userid: userid,
BytesKv: map[uint32]uint32{},
Uint32SKv: map[uint32]uint32{},
FlagsWithExpireKv: map[uint32]*saasapi.FlagWithExpire{},
}
for key, value := range q {
parts := strings.Split(strings.ToLower(key), ".")
if len(parts) == 2 {
switch parts[0] {
case "u8":
index, err := strconv.ParseUint(parts[1], 10, 8)
if err != nil {
reterr = fmt.Errorf("param is error. line %v, param %v", lineNum, key)
return
}
if index == 0 || index > uint64(saasapi.MAX_U8) {
reterr = fmt.Errorf("param index is error. line %v, param %v, index %v", lineNum, key, index)
return
}
nValue, err := strconv.ParseUint(value[0], 10, 8)
if err != nil {
reterr = fmt.Errorf("param value is error. line %v, param %v, value %v", lineNum, key, value)
return
}
writeItem.BytesKv[uint32(index)] = uint32(nValue)
case "u32":
index, err := strconv.ParseUint(parts[1], 10, 8)
if err != nil {
reterr = fmt.Errorf("param is error. line %v, param %v", lineNum, key)
return
}
if index == 0 || index > uint64(saasapi.MAX_U32) {
reterr = fmt.Errorf("param index is error. line %v, param %v, index %v", lineNum, key, index)
return
}
nValue, err := strconv.ParseUint(value[0], 10, 32)
if err != nil {
reterr = fmt.Errorf("param value is error. line %v, param %v, value %v", lineNum, key, value)
return
}
writeItem.Uint32SKv[uint32(index)] = uint32(nValue)
case "flag":
index, err := strconv.ParseUint(parts[1], 10, 8)
if err != nil {
reterr = fmt.Errorf("param is error. line %v, param %v", lineNum, key)
return
}
if index == 0 || index > uint64(saasapi.MAX_FLAG) {
reterr = fmt.Errorf("param index is error. line %v, param %v, index %v", lineNum, key, index)
return
}
flag := &saasapi.FlagWithExpire{}
switch strings.ToLower(value[0]) {
case "true":
flag.Flag = true
case "false":
flag.Flag = false
default:
if strings.HasPrefix(value[0], "!") {
// 相对时间戳
nValue, err := strconv.ParseUint(value[0][1:], 10, 32)
if err != nil {
reterr = fmt.Errorf("param value is error. line %v, param %v, value %v", lineNum, key, value)
return
}
flag.Flag = true
flag.Expire = d.currTimeStamp + uint32(nValue)
} else {
nValue, err := strconv.ParseUint(value[0], 10, 32)
if err != nil || nValue > 30*24*86400 {
reterr = fmt.Errorf("param value is error. line %v, param %v, value %v", lineNum, key, value)
return
}
flag.Flag = true
flag.Expire = uint32(nValue)
}
}
writeItem.FlagsWithExpireKv[uint32(index)] = flag
}
}
}
return
}

46
cmd/saastool/exp.go Normal file
View File

@@ -0,0 +1,46 @@
package main
import (
"fmt"
"os"
"strings"
)
func RunExp(args ...string) error {
name, args := ParseCommandName(args)
// 从参数中解析出命令
switch name {
case "", "help":
return RunExpHelp(args...)
case "list":
return RunExpList(args...)
case "get":
return RunExpGet(args...)
case "grant":
return RunExpGrant(args...)
default:
err := fmt.Errorf(`unknown command "%s"`+"\n"+`Run 'saastool exp help' for usage`, name)
fmt.Fprintln(os.Stderr, err)
return err
}
}
func RunExpHelp(args ...string) error {
fmt.Println(strings.TrimSpace(expUsage))
return nil
}
const expUsage = `
Usage: saastool exp COMMAND [OPTIONS]
Commands:
list List exps
get Get exp report
grant Experiment authorization management
"help" is the default command.
Use "saastool exp COMMAND -help" for more information about a command.
`

182
cmd/saastool/exp_get.go Normal file
View File

@@ -0,0 +1,182 @@
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
bucketIDs []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)
bucketIDs := paramWhereBucketIds(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
}
bucketIDsNumSlice := []uint32{}
if *bucketIDs != "" {
expIDsSlice := strings.Split(*bucketIDs, ",")
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
}
bucketIDsNumSlice = append(bucketIDsNumSlice, uint32(idNum))
}
}
if *beginDay < 20250101 || *beginDay > 21001231 || *endDay < 20250101 || *endDay > 21001231 {
fmt.Fprintln(os.Stderr, "begin/end day error")
fs.PrintDefaults()
return nil
}
if *target == "" {
fmt.Fprintln(os.Stderr, "target error")
fs.PrintDefaults()
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,
},
bucketIDs: bucketIDsNumSlice,
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{
WhereBucketId: getExpParams.bucketIDs,
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
}

40
cmd/saastool/exp_grant.go Normal file
View File

@@ -0,0 +1,40 @@
package main
import (
"fmt"
"os"
"strings"
)
func RunExpGrant(args ...string) error {
name, args := ParseCommandName(args)
switch name {
case "", "help":
fmt.Println(strings.TrimSpace(expGrantUsage))
return nil
case "list":
return RunExpGrantList(args...)
case "add":
return RunExpGrantAdd(args...)
case "delete":
return RunExpGrantDelete(args...)
default:
err := fmt.Errorf(`unknown command "%s"`+"\n"+`Run 'saastool exp grant help' for usage`, name)
fmt.Fprintln(os.Stderr, err)
return err
}
}
const expGrantUsage = `
Usage: saastool exp grant COMMAND [OPTIONS]
Commands:
list List experiment authorization
add Add experiment authorization
delete Delete experiment authorization
"help" is the default command.
Use "saastool exp grant COMMAND -help" for more information about a command.
`

View File

@@ -0,0 +1,81 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type expGrantAddParams struct {
srtaAccountId uint32
saasHttp *saashttp.SaasClient
}
func RunExpGrantAdd(args ...string) error {
fs := flag.NewFlagSet("add", flag.ExitOnError)
cfgFile := paramConfig(fs)
srtaAccountId := paramSrtaAccountId(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
}
if *srtaAccountId == 0 {
fmt.Fprintln(os.Stderr, "Error: sRTA account ID is required")
fs.PrintDefaults()
return fmt.Errorf("sRTA account ID is required")
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
expGrantAddParams := expGrantAddParams{
srtaAccountId: uint32(*srtaAccountId),
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doExpGrantAdd(expGrantAddParams)
}
func doExpGrantAdd(params expGrantAddParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ExpGrantAdd{
ExpGrantAdd: &saasapi.ExpGrant{
TargetAccountId: params.srtaAccountId,
},
},
}
res, err := params.saasHttp.ExpGrantAdd(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Exp Grant Add error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "Exp grant add failed", "code", res.Code, "status", res.Status)
return nil
}
expGrantRes := res.GetExpGrantAddRes()
fmt.Printf("exp grant add res: %v\n", protojson.Format(expGrantRes))
return nil
}

View File

@@ -0,0 +1,81 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type expGrantDeleteParams struct {
srtaAccountId uint32
saasHttp *saashttp.SaasClient
}
func RunExpGrantDelete(args ...string) error {
fs := flag.NewFlagSet("delete", flag.ExitOnError)
cfgFile := paramConfig(fs)
srtaAccountId := paramSrtaAccountId(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
}
if *srtaAccountId == 0 {
fmt.Fprintln(os.Stderr, "Error: sRTA account ID is required")
fs.PrintDefaults()
return fmt.Errorf("sRTA account ID is required")
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
expGrantDeleteParams := expGrantDeleteParams{
srtaAccountId: uint32(*srtaAccountId),
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doExpGrantDelete(expGrantDeleteParams)
}
func doExpGrantDelete(params expGrantDeleteParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ExpGrantDelete{
ExpGrantDelete: &saasapi.ExpGrant{
TargetAccountId: params.srtaAccountId,
},
},
}
res, err := params.saasHttp.ExpGrantDelete(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Exp Grant Delete error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "Exp grant delete failed", "code", res.Code, "status", res.Status)
return nil
}
expGrantRes := res.GetExpGrantDeleteRes()
fmt.Printf("exp grant delete res: %v\n", protojson.Format(expGrantRes))
return nil
}

View File

@@ -0,0 +1,70 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type expGrantListParams struct {
saasHttp *saashttp.SaasClient
}
func RunExpGrantList(args ...string) error {
fs := flag.NewFlagSet("list", flag.ExitOnError)
cfgFile := paramConfig(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
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
expGrantListParams := expGrantListParams{
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doExpGrantList(expGrantListParams)
}
func doExpGrantList(params expGrantListParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ExpGrantList{
ExpGrantList: &saasapi.ExpGrantList{},
},
}
res, err := params.saasHttp.ExpGrantList(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Exp Grant List error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "Exp grant list failed", "code", res.Code, "status", res.Status)
return nil
}
expGrantRes := res.GetExpGrantListRes()
fmt.Printf("exp grant list res: %v\n", protojson.Format(expGrantRes))
return nil
}

71
cmd/saastool/exp_list.go Normal file
View File

@@ -0,0 +1,71 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type listExpParams struct {
saasHttp *saashttp.SaasClient
}
func RunExpList(args ...string) error {
fs := flag.NewFlagSet("list", flag.ExitOnError)
cfgFile := paramConfig(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
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
listExpParams := listExpParams{
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doExpList(listExpParams)
}
func doExpList(listExpParams listExpParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ExpList{
ExpList: &saasapi.ExpList{},
},
}
res, err := listExpParams.saasHttp.ExpList(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit ListExp error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "list exp failed", "code", res.Code, "status", res.Status)
return nil
}
listExpRes := res.GetExpListRes()
fmt.Printf("exp res: %v\n", protojson.Format(listExpRes))
return nil
}

46
cmd/saastool/grant.go Normal file
View File

@@ -0,0 +1,46 @@
package main
import (
"fmt"
"os"
"strings"
)
func RunGrant(args ...string) error {
name, args := ParseCommandName(args)
// 从参数中解析出命令
switch name {
case "", "help":
return RunGrantHelp(args...)
case "list":
return RunGrantList(args...)
case "add":
return RunGrantAdd(args...)
case "delete":
return RunGrantDelete(args...)
default:
err := fmt.Errorf(`unknown command "%s"`+"\n"+`Run 'saastool grant help' for usage`, name)
fmt.Fprintln(os.Stderr, err)
return err
}
}
func RunGrantHelp(args ...string) error {
fmt.Println(strings.TrimSpace(grantUsage))
return nil
}
const grantUsage = `
Usage: saastool grant COMMAND [OPTIONS]
Commands:
list List data grants
add Add data grant
delete Delete data grant
"help" is the default command.
Use "saastool grant COMMAND -help" for more information about a command.
`

101
cmd/saastool/grant_add.go Normal file
View File

@@ -0,0 +1,101 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type grantAddParams struct {
srtaAccountId uint32
grantIndex string
ds uint32
saasHttp *saashttp.SaasClient
}
func RunGrantAdd(args ...string) error {
fs := flag.NewFlagSet("add", flag.ExitOnError)
cfgFile := paramConfig(fs)
srtaAccountId := paramSrtaAccountId(fs)
dsid := paramRawDataSpaceId(fs)
grantIndex := paramGrantIndex(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
}
if *srtaAccountId == 0 {
fmt.Fprintln(os.Stderr, "Error: sRTA account ID is required")
fs.PrintDefaults()
return fmt.Errorf("sRTA account ID is required")
}
if *grantIndex == "" {
fmt.Fprintln(os.Stderr, "Error: grant index is required")
fs.PrintDefaults()
return fmt.Errorf("grant index is required")
}
if *dsid == 0 {
fmt.Fprintln(os.Stderr, "Error: data space ID is required")
fs.PrintDefaults()
return fmt.Errorf("data space ID is required")
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
grantAddParams := grantAddParams{
srtaAccountId: uint32(*srtaAccountId),
grantIndex: *grantIndex,
ds: uint32(*dsid),
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doGrantAdd(grantAddParams)
}
func doGrantAdd(params grantAddParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_GrantAdd{
GrantAdd: &saasapi.Grant{
TargetAccountId: params.srtaAccountId,
GrantIndex: params.grantIndex,
DataspaceId: params.ds,
},
},
}
res, err := params.saasHttp.GrantAdd(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Grant Add error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "Grant add failed", "code", res.Code, "status", res.Status)
return nil
}
grantRes := res.GetGrantAddRes()
fmt.Printf("grant add res: %v\n", protojson.Format(grantRes))
return nil
}

View File

@@ -0,0 +1,101 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type grantDeleteParams struct {
srtaAccountId uint32
grantIndex string
ds uint32
saasHttp *saashttp.SaasClient
}
func RunGrantDelete(args ...string) error {
fs := flag.NewFlagSet("delete", flag.ExitOnError)
cfgFile := paramConfig(fs)
dsid := paramRawDataSpaceId(fs)
srtaAccountId := paramSrtaAccountId(fs)
grantIndex := paramGrantIndex(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
}
if *dsid == 0 {
fmt.Fprintln(os.Stderr, "Error: data space ID is required")
fs.PrintDefaults()
return fmt.Errorf("data space ID is required")
}
if *srtaAccountId == 0 {
fmt.Fprintln(os.Stderr, "Error: sRTA account ID is required")
fs.PrintDefaults()
return fmt.Errorf("sRTA account ID is required")
}
if *grantIndex == "" {
fmt.Fprintln(os.Stderr, "Error: grant index is required")
fs.PrintDefaults()
return fmt.Errorf("grant index is required")
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
grantDeleteParams := grantDeleteParams{
srtaAccountId: uint32(*srtaAccountId),
grantIndex: *grantIndex,
ds: uint32(*dsid),
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doGrantDelete(grantDeleteParams)
}
func doGrantDelete(params grantDeleteParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_GrantDelete{
GrantDelete: &saasapi.Grant{
TargetAccountId: params.srtaAccountId,
GrantIndex: params.grantIndex,
DataspaceId: params.ds,
},
},
}
res, err := params.saasHttp.GrantDelete(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Grant Delete error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "Grant delete failed", "code", res.Code, "status", res.Status)
return nil
}
grantRes := res.GetGrantDeleteRes()
fmt.Printf("grant delete res: %v\n", protojson.Format(grantRes))
return nil
}

View File

@@ -0,0 +1,70 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type grantListParams struct {
saasHttp *saashttp.SaasClient
}
func RunGrantList(args ...string) error {
fs := flag.NewFlagSet("list", flag.ExitOnError)
cfgFile := paramConfig(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
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
grantListParams := grantListParams{
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doGrantList(grantListParams)
}
func doGrantList(params grantListParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_GrantList{
GrantList: &saasapi.GrantList{},
},
}
res, err := params.saasHttp.GrantList(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Grant List error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "Grant list failed", "code", res.Code, "status", res.Status)
return nil
}
grantRes := res.GetGrantListRes()
fmt.Printf("grant list res: %v\n", protojson.Format(grantRes))
return nil
}

View File

@@ -15,13 +15,21 @@ const usage = `
Usage: saastool COMMAND [OPTIONS]
Commands:
info Saas Info
write Write user's 'bytes / uint32s / flags'
read Read user's 'bytes / uint32s / flags'
columnwrite Write columns for 'deviceid / openid' users
convert Convert data to write format
task Task commands
task Task commands
target Target commands
bind Bind commands
grant Grant commands
script Script commands
exp Exp commands
daemon Run in daemon mode
"help" is the default command.

71
cmd/saastool/info.go Normal file
View File

@@ -0,0 +1,71 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type infoParams struct {
saasHttp *saashttp.SaasClient
}
func RunInfo(args ...string) error {
fs := flag.NewFlagSet("info", flag.ExitOnError)
cfgFile := paramConfig(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
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
infoParams := infoParams{
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doInfo(infoParams)
}
func doInfo(infoParams infoParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_Info{
Info: &saasapi.Info{},
},
}
res, err := infoParams.saasHttp.Info(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Info error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "info failed", "code", res.Code, "status", res.Status)
return nil
}
infoRes := res.GetInfoRes()
fmt.Printf("info res: %v\n", protojson.Format(infoRes))
return nil
}

View File

@@ -18,6 +18,8 @@ func Run(args ...string) error {
switch name {
case "", "help":
return RunHelp(args...)
case "info":
return RunInfo(args...)
case "write":
return RunWrite(args...)
case "read":
@@ -30,6 +32,18 @@ func Run(args ...string) error {
return RunVerify(args...)
case "task":
return RunTask(args...)
case "target":
return RunTarget(args...)
case "bind":
return RunBind(args...)
case "grant":
return RunGrant(args...)
case "script":
return RunScript(args...)
case "exp":
return RunExp(args...)
case "daemon":
return RunDaemon(args...)
default:
err := fmt.Errorf(`unknown command "%v"`+"\n"+`Run 'saastool help' for usage`, name)
fmt.Fprintln(os.Stderr, err.Error())

View File

@@ -62,7 +62,7 @@ func paramBatchSize(fs *flag.FlagSet) *uint {
}
func paramBlockSize(fs *flag.FlagSet) *string {
return fs.String("blocksize", "200M", "Block size to make hash. using size mode K, M, G, T")
return fs.String("blocksize", "50M", "Block size to make hash. using size mode K, M, G, T")
}
func paramClear(fs *flag.FlagSet) *bool {
@@ -73,6 +73,98 @@ func paramDataSpaceId(fs *flag.FlagSet) *string {
return fs.String("ds", "", "Data space ID")
}
func paramTargets(fs *flag.FlagSet) *string {
return fs.String("targets", "", "Target IDs. Use commas to separate multiple IDs")
}
func paramListBinds(fs *flag.FlagSet) *bool {
return fs.Bool("b", false, "List Binds")
}
func paramTarget(fs *flag.FlagSet) *string {
return fs.String("target", "", "Target ID")
}
func paramAccount(fs *flag.FlagSet) *int64 {
return fs.Int64("account", 0, "Advertiser ID")
}
func paramAccounts(fs *flag.FlagSet) *string {
return fs.String("accounts", "", "Advertiser IDs. Use commas to separate multiple IDs")
}
func paramAds(fs *flag.FlagSet) *string {
return fs.String("ads", "", "AdGroup IDs. Use commas to separate multiple IDs")
}
func paramIdType(fs *flag.FlagSet) *int {
return fs.Int("idtype", 0, "ID Type. empty is Automatic matching, 1=AdGroup, 3=Account")
}
func paramIDs(fs *flag.FlagSet) *string {
return fs.String("ids", "", "IDs for delete. Use commas to separate multiple IDs")
}
func paramLua(fs *flag.FlagSet) *string {
return fs.String("lua", "", "LUA file name")
}
func paramName(fs *flag.FlagSet) *string {
return fs.String("name", "", "Name")
}
func paramDid(fs *flag.FlagSet) *string {
return fs.String("did", "", "device md5 (lower case)")
}
func paramOS(fs *flag.FlagSet) *uint {
return fs.Uint("os", 2, "1=iOS, 2=Android, 7=Harmony 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 paramWhereBucketIds(fs *flag.FlagSet) *string {
return fs.String("bucketids", "", "Bucket 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")
}
func paramSrtaAccountId(fs *flag.FlagSet) *uint64 {
return fs.Uint64("account", 0, "sRTA account ID")
}
func paramRawDataSpaceId(fs *flag.FlagSet) *uint64 {
return fs.Uint64("ds", 0, "Raw data space ID")
}
func paramGrantIndex(fs *flag.FlagSet) *string {
return fs.String("index", "", "Grant index. Format: \"1, 2, 4, 55-64\"")
}
// ParseByteSize 解析字节大小字符串为字节数
func ParseByteSize(sizeStr string) (uint64, error) {
sizeStr = strings.TrimSpace(sizeStr)

View File

@@ -7,8 +7,8 @@ import (
"os"
"strings"
"e.coding.net/rta/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
@@ -62,7 +62,7 @@ func RunRead(args ...string) error {
ds: *ds,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: &cfg.ApiUrls,
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}

55
cmd/saastool/script.go Normal file
View File

@@ -0,0 +1,55 @@
package main
import (
"fmt"
"os"
"strings"
)
func RunScript(args ...string) error {
name, args := ParseCommandName(args)
// 从参数中解析出命令
switch name {
case "", "help":
return RunScriptHelp(args...)
case "run":
return RunScriptRun(args...)
case "create":
return RunScriptCreate(args...)
case "list":
return RunScriptList(args...)
case "delete":
return RunScriptDelete(args...)
case "get":
return RunScriptGet(args...)
case "use":
return RunScriptUse(args...)
default:
err := fmt.Errorf(`unknown command "%s"`+"\n"+`Run 'saastool script help' for usage`, name)
fmt.Fprintln(os.Stderr, err)
return err
}
}
func RunScriptHelp(args ...string) error {
fmt.Println(strings.TrimSpace(scriptUsage))
return nil
}
const scriptUsage = `
Usage: saastool script COMMAND [OPTIONS]
Commands:
run Run lua script test on server
create Create lua script on server
list List all scripts on server
delete Delete a script from server
get Get script content from server
use Use a script as default
"help" is the default command.
Use "saastool script COMMAND -help" for more information about a command.
`

View File

@@ -0,0 +1,94 @@
package main
import (
"flag"
"fmt"
"io"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type scriptCreateParams struct {
luaName string
luaScript string
saasHttp *saashttp.SaasClient
}
func RunScriptCreate(args ...string) error {
fs := flag.NewFlagSet("create", flag.ExitOnError)
cfgFile := paramConfig(fs)
luaFile := paramLua(fs)
luaName := paramName(fs)
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err)
return err
}
if fs.NArg() > 0 || len(*luaFile) == 0 || len(*luaName) == 0 {
fs.PrintDefaults()
return nil
}
file, err := os.Open(*luaFile)
if err != nil {
fmt.Fprintln(os.Stderr, "lua file error", "err", err)
return err
}
defer file.Close()
body, err := io.ReadAll(file)
if err != nil {
fmt.Fprintln(os.Stderr, "lua file read error", "err", err)
return err
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
scriptCreateParams := scriptCreateParams{
luaName: *luaName,
luaScript: string(body),
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doScriptCreate(scriptCreateParams)
}
func doScriptCreate(scriptCreateParams scriptCreateParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ScriptCreate{
ScriptCreate: &saasapi.ScriptCreate{
LuaName: scriptCreateParams.luaName,
LuaScript: scriptCreateParams.luaScript,
},
},
}
res, err := scriptCreateParams.saasHttp.ScriptCreate(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Create Script error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "script create failed", "code", res.Code, "status", res.Status)
return nil
}
scriptRes := res.GetScriptCreateRes()
fmt.Printf("script res: %v\n", protojson.Format(scriptRes))
return nil
}

View File

@@ -0,0 +1,76 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type scriptDeleteParams struct {
luaName string
saasHttp *saashttp.SaasClient
}
func RunScriptDelete(args ...string) error {
fs := flag.NewFlagSet("delete", flag.ExitOnError)
cfgFile := paramConfig(fs)
luaName := paramName(fs)
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err)
return err
}
if fs.NArg() > 0 || len(*luaName) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
scriptDeleteParams := scriptDeleteParams{
luaName: *luaName,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doScriptDelete(scriptDeleteParams)
}
func doScriptDelete(scriptDeleteParams scriptDeleteParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ScriptDelete{
ScriptDelete: &saasapi.ScriptDelete{
LuaName: scriptDeleteParams.luaName,
},
},
}
res, err := scriptDeleteParams.saasHttp.ScriptDelete(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Delete Script error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "script delete failed", "code", res.Code, "status", res.Status)
return nil
}
scriptRes := res.GetScriptDeleteRes()
fmt.Printf("script res: %v\n", protojson.Format(scriptRes))
return nil
}

View File

@@ -0,0 +1,76 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type scriptGetParams struct {
luaName string
saasHttp *saashttp.SaasClient
}
func RunScriptGet(args ...string) error {
fs := flag.NewFlagSet("get", flag.ExitOnError)
cfgFile := paramConfig(fs)
luaName := paramName(fs)
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err)
return err
}
if fs.NArg() > 0 || len(*luaName) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
scriptGetParams := scriptGetParams{
luaName: *luaName,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doScriptGet(scriptGetParams)
}
func doScriptGet(scriptGetParams scriptGetParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ScriptGet{
ScriptGet: &saasapi.ScriptGet{
LuaName: scriptGetParams.luaName,
},
},
}
res, err := scriptGetParams.saasHttp.ScriptGet(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Get Script error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "script get failed", "code", res.Code, "status", res.Status)
return nil
}
scriptRes := res.GetScriptGetRes()
fmt.Printf("script res: %v\n", protojson.Format(scriptRes))
return nil
}

View File

@@ -0,0 +1,71 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type scriptListParams struct {
saasHttp *saashttp.SaasClient
}
func RunScriptList(args ...string) error {
fs := flag.NewFlagSet("list", flag.ExitOnError)
cfgFile := paramConfig(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
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
scriptListParams := scriptListParams{
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doScriptList(scriptListParams)
}
func doScriptList(scriptListParams scriptListParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ScriptList{
ScriptList: &saasapi.ScriptList{},
},
}
res, err := scriptListParams.saasHttp.ScriptList(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit List Script error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "script list failed", "code", res.Code, "status", res.Status)
return nil
}
scriptRes := res.GetScriptListRes()
fmt.Printf("script res: %v\n", protojson.Format(scriptRes))
return nil
}

112
cmd/saastool/script_run.go Normal file
View File

@@ -0,0 +1,112 @@
package main
import (
"flag"
"fmt"
"io"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
)
type scriptRunParams struct {
luaScript string
did string
os saasapi.OS
saasHttp *saashttp.SaasClient
}
func RunScriptRun(args ...string) error {
fs := flag.NewFlagSet("run", flag.ExitOnError)
cfgFile := paramConfig(fs)
luaFile := paramLua(fs)
did := paramDid(fs)
tos := paramOS(fs)
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err)
return err
}
if fs.NArg() > 0 || len(*luaFile) == 0 || len(*did) == 0 {
fs.PrintDefaults()
return nil
}
if !(*tos == 1 || *tos == 2 || *tos == 7) {
fmt.Fprintln(os.Stderr, "OS error")
return nil
}
file, err := os.Open(*luaFile)
if err != nil {
fmt.Fprintln(os.Stderr, "lua file error", "err", err)
return err
}
defer file.Close()
body, err := io.ReadAll(file)
if err != nil {
fmt.Fprintln(os.Stderr, "lua file read error", "err", err)
return err
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
scriptRunParams := scriptRunParams{
luaScript: string(body),
did: *did,
os: saasapi.OS(*tos),
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doScriptRun(scriptRunParams)
}
func doScriptRun(scriptRunParams scriptRunParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ScriptRun{
ScriptRun: &saasapi.ScriptRun{
LuaScript: scriptRunParams.luaScript,
ServerDid: scriptRunParams.did,
Os: scriptRunParams.os,
},
},
}
res, err := scriptRunParams.saasHttp.ScriptRun(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "run script error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
err = fmt.Errorf("run script failed. code:%v, status:%v", res.Code, res.Status)
fmt.Fprintln(os.Stderr, err)
return err
}
scriptRunRes := res.GetScriptRunRes()
fmt.Println("ERROROUT_OUTPUT:")
fmt.Print(scriptRunRes.GetErrorOutput())
fmt.Println()
fmt.Println("PRINT_OUTPUT:")
fmt.Print(scriptRunRes.GetPrintOutput())
fmt.Println()
fmt.Println("DATASPACE_OUTPUT:")
fmt.Print(scriptRunRes.GetDataspaceOut())
fmt.Println()
fmt.Println("TARGETS_OUTPUT:")
fmt.Print(scriptRunRes.GetTargetsOutput())
return nil
}

View File

@@ -0,0 +1,76 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type scriptUseParams struct {
luaName string
saasHttp *saashttp.SaasClient
}
func RunScriptUse(args ...string) error {
fs := flag.NewFlagSet("use", flag.ExitOnError)
cfgFile := paramConfig(fs)
luaName := paramName(fs)
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err)
return err
}
if fs.NArg() > 0 || len(*luaName) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
scriptUseParams := scriptUseParams{
luaName: *luaName,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doScriptUse(scriptUseParams)
}
func doScriptUse(scriptUseParams scriptUseParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ScriptUse{
ScriptUse: &saasapi.ScriptUse{
LuaName: scriptUseParams.luaName,
},
},
}
res, err := scriptUseParams.saasHttp.ScriptUse(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Use Script error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "script use failed", "code", res.Code, "status", res.Status)
return nil
}
scriptRes := res.GetScriptUseRes()
fmt.Printf("script use res: %v\n", protojson.Format(scriptRes))
return nil
}

46
cmd/saastool/target.go Normal file
View File

@@ -0,0 +1,46 @@
package main
import (
"fmt"
"os"
"strings"
)
func RunTarget(args ...string) error {
name, args := ParseCommandName(args)
// 从参数中解析出命令
switch name {
case "", "help":
return RunTargetHelp(args...)
case "list":
return RunTargetList(args...)
case "create":
return RunTargetCreate(args...)
case "delete":
return RunTargetDelete(args...)
default:
err := fmt.Errorf(`unknown command "%s"`+"\n"+`Run 'saastool target help' for usage`, name)
fmt.Fprintln(os.Stderr, err)
return err
}
}
func RunTargetHelp(args ...string) error {
fmt.Println(strings.TrimSpace(targetUsage))
return nil
}
const targetUsage = `
Usage: saastoola target COMMAND [OPTIONS]
Commands:
list List targets
create Create a new target
delete Delete an existing target
"help" is the default command.
Use "saastool target COMMAND -help" for more information about a command.
`

View File

@@ -1,38 +0,0 @@
package main
import (
"encoding/json"
"os"
)
// MapConfig 配置
type MapConfig struct {
Targets map[string]*Target `json:"targets"`
}
// Target 配置
type Target struct {
WriteByte *byte `json:"write_byte"` // byte值
WriteBytePos int `json:"write_byte_pos"` // byte写入位置
WriteUint32 *uint32 `json:"write_uint32"` // uint32值
WriteUint32Pos int `json:"write_uint32_pos"` // uint32写入位置
WriteFlag *bool `json:"write_flag"` // 标志位
WriteExpire *uint32 `json:"write_expire"` // 过期时间
WriteFlagWithExpirePos int `json:"write_flag_with_expire_pos"` // 标志与过期写入位置
}
// LoadConfigFile 加载配置文件
func LoadMapFile(filename string) (*MapConfig, error) {
// 打开文件
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
sc := &MapConfig{}
err = json.NewDecoder(f).Decode(sc)
return sc, err
}

View File

@@ -0,0 +1,81 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type createTargetParams struct {
targetId string
targetDesc string
saasHttp *saashttp.SaasClient
}
func RunTargetCreate(args ...string) error {
fs := flag.NewFlagSet("create", flag.ExitOnError)
cfgFile := paramConfig(fs)
targetId := paramTarget(fs)
targetDesc := paramTaskDesc(fs)
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err)
return err
}
if fs.NArg() > 0 || len(*targetId) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
createTargetParams := createTargetParams{
targetId: *targetId,
targetDesc: *targetDesc,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doTargetCreate(createTargetParams)
}
func doTargetCreate(createTargetParams createTargetParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_TargetCreate{
TargetCreate: &saasapi.TargetCreate{
TargetId: createTargetParams.targetId,
TargetDescription: createTargetParams.targetDesc,
},
},
}
res, err := createTargetParams.saasHttp.TargetCreate(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Create Target error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "target create failed", "code", res.Code, "status", res.Status)
return nil
}
targetRes := res.GetTargetCreateRes()
fmt.Printf("target res: %v\n", protojson.Format(targetRes))
return nil
}

View File

@@ -0,0 +1,76 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type deleteTargetParams struct {
targetId string
saasHttp *saashttp.SaasClient
}
func RunTargetDelete(args ...string) error {
fs := flag.NewFlagSet("delete", flag.ExitOnError)
cfgFile := paramConfig(fs)
targetId := paramTarget(fs)
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err)
return err
}
if fs.NArg() > 0 || len(*targetId) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
deleteTargetParams := deleteTargetParams{
targetId: *targetId,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doTargetDelete(deleteTargetParams)
}
func doTargetDelete(deleteTargetParams deleteTargetParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_TargetDelete{
TargetDelete: &saasapi.TargetDelete{
TargetId: deleteTargetParams.targetId,
},
},
}
res, err := deleteTargetParams.saasHttp.TargetDelete(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit Target delete error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
err = fmt.Errorf("target delete failed. code:%v, status:%v", res.Code, res.Status)
fmt.Fprintln(os.Stderr, err)
return err
}
targetDeleteRes := res.GetTargetDeleteRes()
fmt.Printf("target res: %v\n", protojson.Format(targetDeleteRes))
return nil
}

View File

@@ -0,0 +1,88 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"strings"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type listTargetParams struct {
targets []string
listBinds bool
saasHttp *saashttp.SaasClient
}
func RunTargetList(args ...string) error {
fs := flag.NewFlagSet("list", flag.ExitOnError)
cfgFile := paramConfig(fs)
targets := paramTargets(fs)
listBinds := paramListBinds(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
}
// 切割字符串
idsSlice := strings.Split(*targets, ",")
if len(idsSlice) == 1 && idsSlice[0] == "" {
idsSlice = []string{}
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
listTargetParams := listTargetParams{
listBinds: *listBinds,
targets: idsSlice,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doTargetList(listTargetParams)
}
func doTargetList(listTargetParams listTargetParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_TargetList{
TargetList: &saasapi.TargetList{
Targets: listTargetParams.targets,
ListBind: listTargetParams.listBinds,
},
},
}
res, err := listTargetParams.saasHttp.TargetList(saasReq)
if err != nil {
fmt.Fprintln(os.Stderr, "submit List Target error", "err", err)
return err
}
if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "Target list failed", "code", res.Code, "status", res.Status)
return nil
}
targetRes := res.GetTargetListRes()
fmt.Printf("target res: %v\n", protojson.Format(targetRes))
return nil
}

View File

@@ -25,6 +25,8 @@ func RunTask(args ...string) error {
return RunTaskInfo(args...)
case "upload":
return RunTaskUpload(args...)
case "download":
return RunTaskDownload(args...)
case "run":
return RunTaskRun(args...)
default:
@@ -51,6 +53,7 @@ Commands:
delete Delete a task on server
info Get a task info on server
upload Upload task's file block to server
download Download task's file block to local
"help" is the default command.

View File

@@ -6,8 +6,8 @@ import (
"net/http"
"os"
"e.coding.net/rta/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
@@ -42,7 +42,7 @@ func RunTaskCreate(args ...string) error {
hashFile: *hashFile,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: &cfg.ApiUrls,
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
task: &saasapi.Task{},

View File

@@ -6,8 +6,8 @@ import (
"net/http"
"os"
"e.coding.net/rta/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
@@ -41,7 +41,7 @@ func RunTaskDelete(args ...string) error {
taskSha256: *sha256,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: &cfg.ApiUrls,
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}

View File

@@ -0,0 +1,134 @@
package main
import (
"flag"
"fmt"
"net/http"
"os"
"path/filepath"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
)
type downloadTaskParams struct {
taskSha256 string
destPath string
saasHttp *saashttp.SaasClient
}
func RunTaskDownload(args ...string) error {
fs := flag.NewFlagSet("download", flag.ExitOnError)
cfgFile := paramConfig(fs)
sha256 := paramSha256(fs)
destPath := paramDestPath(fs)
if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err)
return err
}
if fs.NArg() > 0 || len(*sha256) == 0 || len(*destPath) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err)
return err
}
downloadTaskParams := downloadTaskParams{
taskSha256: *sha256,
destPath: *destPath,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doTaskDownload(downloadTaskParams)
}
func doTaskDownload(downloadTaskParams downloadTaskParams) error {
infoTaskParams := infoTaskParams{
taskSha256: downloadTaskParams.taskSha256,
saasHttp: downloadTaskParams.saasHttp,
}
taskInfo, err := doTaskInfo(infoTaskParams)
if err != nil {
return err
}
if len(taskInfo.GetSourcePath()) == 0 {
err = fmt.Errorf("task download failed. task info source path is empty")
fmt.Fprintln(os.Stderr, err)
return err
}
totalFiles := len(taskInfo.GetTaskFileInfos())
fi := 0
for _, finfo := range taskInfo.GetTaskFileInfos() {
fi++
var f *os.File
offset := int64(0)
totalBlocks := len(finfo.GetFileBlocks())
bi := 0
for _, binfo := range finfo.GetFileBlocks() {
bi++
if binfo.GetUploaded() {
if f == nil {
fname := finfo.GetFileName()
if len(downloadTaskParams.destPath) > 0 {
fname = filepath.Join(downloadTaskParams.destPath, fname)
}
os.MkdirAll(filepath.Dir(fname), os.ModePerm)
f, err = os.Create(fname)
if err != nil {
return err
}
}
blockRes, err := downloadTaskParams.saasHttp.TaskDownload(
binfo.GetBlockSha256(),
f,
offset,
int(binfo.GetBlockLength()),
)
if err != nil {
return err
}
if blockRes.GetCode() != saasapi.ErrorCode_SUCC {
err = fmt.Errorf("download block error, code %d, msg %s", blockRes.GetCode(), blockRes.GetStatus())
fmt.Fprintln(os.Stderr, err)
return err
} else {
fmt.Printf("download block success. file: %v, sha256 %v. block %v/%v, file %v/%v\n",
finfo.GetFileName(), binfo.GetBlockSha256(),
bi, totalBlocks, fi, totalFiles,
)
}
} else {
fmt.Printf("download block. file: %v, sha256 %v. block %v/%v, file %v/%v\n",
finfo.GetFileName(), binfo.GetBlockSha256(),
bi, totalBlocks, fi, totalFiles,
)
}
offset += int64(binfo.GetBlockLength())
}
if f != nil {
f.Close()
}
}
return nil
}

View File

@@ -6,8 +6,8 @@ import (
"net/http"
"os"
"e.coding.net/rta/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
@@ -17,7 +17,7 @@ type infoTaskParams struct {
}
func RunTaskInfo(args ...string) error {
fs := flag.NewFlagSet("create", flag.ExitOnError)
fs := flag.NewFlagSet("info", flag.ExitOnError)
cfgFile := paramConfig(fs)
sha256 := paramSha256(fs)
@@ -41,7 +41,7 @@ func RunTaskInfo(args ...string) error {
taskSha256: *sha256,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: &cfg.ApiUrls,
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}

View File

@@ -6,8 +6,8 @@ import (
"net/http"
"os"
"e.coding.net/rta/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
@@ -17,7 +17,7 @@ type listTaskParams struct {
}
func RunTaskList(args ...string) error {
fs := flag.NewFlagSet("create", flag.ExitOnError)
fs := flag.NewFlagSet("list", flag.ExitOnError)
cfgFile := paramConfig(fs)
filter := paramFilterStatus(fs)
@@ -40,7 +40,7 @@ func RunTaskList(args ...string) error {
listTaskParams := listTaskParams{
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: &cfg.ApiUrls,
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}

View File

@@ -7,12 +7,13 @@ import (
"fmt"
"os"
"path"
"path/filepath"
"runtime"
"sort"
"strings"
"sync"
"e.coding.net/rta/public/saasapi"
"git.algo.com.cn/public/saasapi"
"google.golang.org/protobuf/encoding/protojson"
)
@@ -73,7 +74,6 @@ func RunTaskMake(args ...string) error {
fmt.Fprintln(os.Stderr, "Error parsing block size", "err", err)
fmt.Fprintln(os.Stderr, "Using default 200M")
blockSizeNum = 200 * 1024 * 1024
}
if blockSizeNum < blockSizeMin || blockSizeNum > blockSizeMax {
@@ -81,7 +81,7 @@ func RunTaskMake(args ...string) error {
return nil
}
makeTaskParams := makeTaskParams{
makeTaskParams := &makeTaskParams{
sourcePath: *sourcePath,
hashFile: *hashFile,
task: &saasapi.Task{
@@ -89,12 +89,13 @@ func RunTaskMake(args ...string) error {
TaskDescription: *desc,
Appid: *appid,
DataspaceId: *ds,
SourcePath: *sourcePath,
},
}
return doMakeHash(makeTaskParams)
return doMakeHash(makeTaskParams, true)
}
func doMakeHash(makeTaskParams makeTaskParams) error {
func doMakeHash(makeTaskParams *makeTaskParams, firstLevel bool) error {
fsInfo, err := os.Stat(makeTaskParams.sourcePath)
if err != nil {
return err
@@ -102,29 +103,39 @@ func doMakeHash(makeTaskParams makeTaskParams) error {
if !fsInfo.IsDir() {
// 如果是文件,直接计算
return doTaskMake(makeTaskParams)
}
// 读取目录下信息
dirEntry, err := os.ReadDir(makeTaskParams.sourcePath)
if err != nil {
return err
}
// 遍历目录
for _, dir := range dirEntry {
newParam := makeTaskParams
newParam.sourcePath = path.Join(makeTaskParams.sourcePath, dir.Name())
if err = doMakeHash(newParam); err != nil {
if firstLevel {
makeTaskParams.task.SourcePath = filepath.Dir(makeTaskParams.sourcePath)
}
err = doTaskMake(makeTaskParams)
if err != nil {
return err
}
} else {
// 读取目录下信息
dirEntry, err := os.ReadDir(makeTaskParams.sourcePath)
if err != nil {
return err
}
// 遍历目录
for _, dir := range dirEntry {
oldSourcePath := makeTaskParams.sourcePath
makeTaskParams.sourcePath = path.Join(makeTaskParams.sourcePath, dir.Name())
if err = doMakeHash(makeTaskParams, false); err != nil {
return err
}
makeTaskParams.sourcePath = oldSourcePath
}
}
return saveTaskFile(makeTaskParams)
if firstLevel {
return saveTaskFile(makeTaskParams)
}
return nil
}
func doTaskMake(makeTaskParams makeTaskParams) error {
func doTaskMake(makeTaskParams *makeTaskParams) error {
sourceFile, err := os.Open(makeTaskParams.sourcePath)
if err != nil {
return err
@@ -200,10 +211,12 @@ func doTaskMake(makeTaskParams makeTaskParams) error {
})
// 输出结果
relPath, _ := filepath.Rel(makeTaskParams.task.GetSourcePath(), makeTaskParams.sourcePath)
fileInfo := &saasapi.FileInfo{
FileName: makeTaskParams.sourcePath,
FileName: relPath,
FileSize: uint64(fi.Size()),
}
for _, r := range allResults {
fileInfo.FileBlocks = append(fileInfo.FileBlocks, &saasapi.FileBlock{
BlockSha256: r.hash,
@@ -212,6 +225,8 @@ func doTaskMake(makeTaskParams makeTaskParams) error {
}
makeTaskParams.task.TaskFileInfos = append(makeTaskParams.task.TaskFileInfos, fileInfo)
makeTaskParams.task.TaskSize += uint64(fi.Size())
fmt.Println("")
return nil
}
@@ -227,7 +242,7 @@ func hashWorker(tasks <-chan *hashTask, results chan<- *hashTask) {
}
}
func saveTaskFile(makeTaskParams makeTaskParams) error {
func saveTaskFile(makeTaskParams *makeTaskParams) error {
taskFile, err := os.Create(makeTaskParams.hashFile)
if err != nil {
return err

View File

@@ -6,8 +6,8 @@ import (
"net/http"
"os"
"e.coding.net/rta/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
@@ -17,7 +17,7 @@ type runTaskParams struct {
}
func RunTaskRun(args ...string) error {
fs := flag.NewFlagSet("create", flag.ExitOnError)
fs := flag.NewFlagSet("run", flag.ExitOnError)
cfgFile := paramConfig(fs)
sha256 := paramSha256(fs)
@@ -41,7 +41,7 @@ func RunTaskRun(args ...string) error {
taskSha256: *sha256,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: &cfg.ApiUrls,
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}

View File

@@ -5,9 +5,10 @@ import (
"fmt"
"net/http"
"os"
"path/filepath"
"e.coding.net/rta/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
)
type uploadTaskParams struct {
@@ -40,14 +41,14 @@ func RunTaskUpload(args ...string) error {
taskSha256: *sha256,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: &cfg.ApiUrls,
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doTaskUpload(uploadTaskParams)
}
func doTaskUpload(uploadTaskParams uploadTaskParams) error {
infoTaskParams := infoTaskParams{
taskSha256: uploadTaskParams.taskSha256,
@@ -58,10 +59,10 @@ func doTaskUpload(uploadTaskParams uploadTaskParams) error {
return err
}
sourcePath := taskInfo.GetSourcePath()
totalFiles := len(taskInfo.GetTaskFileInfos())
fi := 0
for _, finfo := range taskInfo.GetTaskFileInfos() {
fi++
var f *os.File
offset := int64(0)
@@ -71,7 +72,11 @@ func doTaskUpload(uploadTaskParams uploadTaskParams) error {
bi++
if !binfo.GetUploaded() {
if f == nil {
f, err = os.Open(finfo.GetFileName())
fname := finfo.GetFileName()
if len(sourcePath) > 0 {
fname = filepath.Join(sourcePath, fname)
}
f, err = os.Open(fname)
if err != nil {
return err
}
@@ -89,7 +94,9 @@ func doTaskUpload(uploadTaskParams uploadTaskParams) error {
}
if blockRes.GetCode() != saasapi.ErrorCode_SUCC {
return fmt.Errorf("upload block error, code %d, msg %s", blockRes.GetCode(), blockRes.GetStatus())
err = fmt.Errorf("upload block error, code %d, msg %s", blockRes.GetCode(), blockRes.GetStatus())
fmt.Fprintln(os.Stderr, err)
return err
} else {
fmt.Printf("upload block success. file: %v, sha256 %v. block %v/%v, file %v/%v\n",
finfo.GetFileName(), binfo.GetBlockSha256(),

View File

@@ -1,25 +0,0 @@
package main
import (
"os"
"syscall"
"unsafe"
)
// https://man7.org/linux/man-pages/man2/TIOCSWINSZ.2const.html
// winSize console窗口大小
type winSize struct {
wsRow uint16
wsCols uint16
wsXPixels uint16
wxYPixels uint16
}
// getConsoleSize 获取控制台窗口大小
func getConsoleSize() (cols, rows int) {
var sz winSize
_, _, _ = syscall.Syscall(syscall.SYS_IOCTL,
os.Stdout.Fd(), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&sz)))
return int(sz.wsCols), int(sz.wsRow)
}

View File

@@ -9,8 +9,8 @@ import (
"path"
"strings"
"e.coding.net/rta/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
@@ -63,7 +63,7 @@ func RunWrite(args ...string) error {
clear: *clear,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: &cfg.ApiUrls,
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}

1
datasample/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
_*

1
datasample/test.txt Normal file
View File

@@ -0,0 +1 @@
{"userid":"test_user", "writeBytes": {"bytes": "AQ==", "index1": "1"}, "writeUint32s": {"uint32s": [112547657,28270208],"index1": "3"}}

2
datasample/testv2.txt Normal file
View File

@@ -0,0 +1,2 @@
{"userid":"test_user", "bytesKv": {"1": 1,"2": 2,"3": 3,"4": 4,"5": 50,"6": 6,"40": 40,"55": 55,"100": 100}, "uint32sKv": {"1": 100000,"2": 200000,"3": 300000,"4": 400000,"5": 500000,"6": 600000,"55": 5500000,"100": 10000000},"flagsWithExpireKv": {"1": {"flag": true,"expire": 1865854386},"2": {"flag": false,"expire": 1865854386}, "64": {"expire": 1765854386}}}
{"userid":"test_succ", "bytesKv": {"1": 1,"2": 2,"3": 3,"4": 4,"5": 50,"6": 6,"40": 40,"55": 55}, "uint32sKv": {"1": 100000,"2": 200000,"3": 300000,"4": 400000,"5": 500000,"6": 600000,"55": 5500000},"flagsWithExpireKv": {"1": {"flag": true,"expire": 1865854386},"2": {"flag": false,"expire": 1865854386}}}

10
docker/build_saastool.sh Executable file
View File

@@ -0,0 +1,10 @@
#/bin/sh -v
set -e
docker buildx build --platform linux/amd64 \
-t rta-docker.pkg.coding.net/public/docker/saastool:latest \
-t rta-docker.pkg.coding.net/public/docker/saastool:2025121617 \
-o type=registry \
-f saastool.Dockerfile \
../ ;

View File

@@ -0,0 +1,16 @@
FROM rta-docker.pkg.coding.net/public/docker/entre_dev:latest AS builder
COPY . /tmp/saasapi/
WORKDIR /tmp/saasapi/
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg \
./make.sh
FROM rta-docker.pkg.coding.net/public/docker/alpine:latest AS product
COPY --from=builder /tmp/saasapi/build/saastool /bin/saastool
EXPOSE 8080
CMD ["saastool", "daemon"]

2
go.mod
View File

@@ -1,4 +1,4 @@
module e.coding.net/rta/public/saasapi
module git.algo.com.cn/public/saasapi
go 1.23.4

8
make.sh Executable file
View File

@@ -0,0 +1,8 @@
cd cmd/saastool
go build -o ../../build/saastool
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ../../build/saastool_linux_x64
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o ../../build/saastool_win_x64
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o ../../build/saastool_mac_x64
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o ../../build/saastool_mac_arm64
cd ../../

View File

@@ -1,19 +1,250 @@
package saashttp
type ApiUrls struct {
BaseUrl string
WritePath string
ReadPath string
ColumnWritePath string
TaskCreatePath string
TaskListPath string
TaskInfoPath string
TaskDeletePath string
TaskRunPath string
TaskUploadPath string
}
const (
baseUrl = "https://api.rta.qq.com"
infoPath = "/saas/info"
writePath = "/saas/write"
readPath = "/saas/read"
columnWritePath = "/saas/column_write"
taskCreatePath = "/saas/task/create"
taskListPath = "/saas/task/list"
taskInfoPath = "/saas/task/info"
taskUploadPath = "/saas/task/upload"
taskDownloadPath = "/saas/task/download"
taskDeletePath = "/saas/task/delete"
taskRunPath = "/saas/task/run"
targetListPath = "/saas/target/list"
targetCreatePath = "/saas/target/create"
targetDeletePath = "/saas/target/delete"
bindSetPath = "/saas/bind/set"
bindDeletePath = "/saas/bind/delete"
scriptRunPath = "/saas/script/run"
scriptCreatePath = "/saas/script/create"
scriptListPath = "/saas/script/list"
scriptDeletePath = "/saas/script/delete"
scriptGetPath = "/saas/script/get"
scriptUsePath = "/saas/script/use"
expListPath = "/saas/exp/list"
expGetPath = "/saas/exp/get"
expGrantListPath = "/saas/exp/grant/list"
expGrantAddPath = "/saas/exp/grant/add"
expGrantDeletePath = "/saas/exp/grant/delete"
grantListPath = "/saas/grant/list"
grantAddPath = "/saas/grant/add"
grantDeletePath = "/saas/grant/delete"
)
type Auth struct {
Account string
Token string
}
type ApiUrls struct {
BaseUrl string
InfoPath string
WritePath string
ReadPath string
ColumnWritePath string
TaskCreatePath string
TaskListPath string
TaskInfoPath string
TaskDeletePath string
TaskRunPath string
TaskUploadPath string
TaskDownloadPath string
TargetListPath string
TargetCreatePath string
TargetDeletePath string
BindSetPath string
BindDeletePath string
ScriptRunPath string
ScriptCreatePath string
ScriptListPath string
ScriptDeletePath string
ScriptGetPath string
ScriptUsePath string
ExpListPath string
ExpGetPath string
ExpGrantListPath string
ExpGrantAddPath string
ExpGrantDeletePath string
GrantListPath string
GrantAddPath string
GrantDeletePath string
}
func InitAPIUrl(c *ApiUrls) *ApiUrls {
r := &ApiUrls{}
if c.BaseUrl != "" {
r.BaseUrl = c.BaseUrl
} else {
r.BaseUrl = baseUrl
}
if c.InfoPath != "" {
r.InfoPath = c.InfoPath
} else {
r.InfoPath = infoPath
}
if c.WritePath != "" {
r.WritePath = c.WritePath
} else {
r.WritePath = writePath
}
if c.ReadPath != "" {
r.ReadPath = c.ReadPath
} else {
r.ReadPath = readPath
}
if c.ColumnWritePath != "" {
r.ColumnWritePath = c.ColumnWritePath
} else {
r.ColumnWritePath = columnWritePath
}
if c.TaskCreatePath != "" {
r.TaskCreatePath = c.TaskCreatePath
} else {
r.TaskCreatePath = taskCreatePath
}
if c.TaskListPath != "" {
r.TaskListPath = c.TaskListPath
} else {
r.TaskListPath = taskListPath
}
if c.TaskInfoPath != "" {
r.TaskInfoPath = c.TaskInfoPath
} else {
r.TaskInfoPath = taskInfoPath
}
if c.TaskDeletePath != "" {
r.TaskDeletePath = c.TaskDeletePath
} else {
r.TaskDeletePath = taskDeletePath
}
if c.TaskRunPath != "" {
r.TaskRunPath = c.TaskRunPath
} else {
r.TaskRunPath = taskRunPath
}
if c.TaskUploadPath != "" {
r.TaskUploadPath = c.TaskUploadPath
} else {
r.TaskUploadPath = taskUploadPath
}
if c.TaskDownloadPath != "" {
r.TaskDownloadPath = c.TaskDownloadPath
} else {
r.TaskDownloadPath = taskDownloadPath
}
if c.TargetListPath != "" {
r.TargetListPath = c.TargetListPath
} else {
r.TargetListPath = targetListPath
}
if c.TargetCreatePath != "" {
r.TargetCreatePath = c.TargetCreatePath
} else {
r.TargetCreatePath = targetCreatePath
}
if c.TargetDeletePath != "" {
r.TargetDeletePath = c.TargetDeletePath
} else {
r.TargetDeletePath = targetDeletePath
}
if c.BindSetPath != "" {
r.BindSetPath = c.BindSetPath
} else {
r.BindSetPath = bindSetPath
}
if c.BindDeletePath != "" {
r.BindDeletePath = c.BindDeletePath
} else {
r.BindDeletePath = bindDeletePath
}
if c.ScriptRunPath != "" {
r.ScriptRunPath = c.ScriptRunPath
} else {
r.ScriptRunPath = scriptRunPath
}
if c.ScriptCreatePath != "" {
r.ScriptCreatePath = c.ScriptCreatePath
} else {
r.ScriptCreatePath = scriptCreatePath
}
if c.ScriptListPath != "" {
r.ScriptListPath = c.ScriptListPath
} else {
r.ScriptListPath = scriptListPath
}
if c.ScriptDeletePath != "" {
r.ScriptDeletePath = c.ScriptDeletePath
} else {
r.ScriptDeletePath = scriptDeletePath
}
if c.ScriptGetPath != "" {
r.ScriptGetPath = c.ScriptGetPath
} else {
r.ScriptGetPath = scriptGetPath
}
if c.ScriptUsePath != "" {
r.ScriptUsePath = c.ScriptUsePath
} else {
r.ScriptUsePath = scriptUsePath
}
if c.ExpListPath != "" {
r.ExpListPath = c.ExpListPath
} else {
r.ExpListPath = expListPath
}
if c.ExpGetPath != "" {
r.ExpGetPath = c.ExpGetPath
} else {
r.ExpGetPath = expGetPath
}
if c.ExpGrantListPath != "" {
r.ExpGrantListPath = c.ExpGrantListPath
} else {
r.ExpGrantListPath = expGrantListPath
}
if c.ExpGrantAddPath != "" {
r.ExpGrantAddPath = c.ExpGrantAddPath
} else {
r.ExpGrantAddPath = expGrantAddPath
}
if c.ExpGrantDeletePath != "" {
r.ExpGrantDeletePath = c.ExpGrantDeletePath
} else {
r.ExpGrantDeletePath = expGrantDeletePath
}
if c.GrantListPath != "" {
r.GrantListPath = c.GrantListPath
} else {
r.GrantListPath = grantListPath
}
if c.GrantAddPath != "" {
r.GrantAddPath = c.GrantAddPath
} else {
r.GrantAddPath = grantAddPath
}
if c.GrantDeletePath != "" {
r.GrantDeletePath = c.GrantDeletePath
} else {
r.GrantDeletePath = grantDeletePath
}
return r
}

View File

@@ -12,9 +12,10 @@ import (
"net/url"
"os"
"strconv"
"strings"
"time"
"e.coding.net/rta/public/saasapi"
"git.algo.com.cn/public/saasapi"
"google.golang.org/protobuf/proto"
)
@@ -32,6 +33,11 @@ type SaasClient struct {
ResponseEncoder ResponseEncoder
}
func (c *SaasClient) Info(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.InfoPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) Write(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.WritePath)
return c.post(postUrl, saasReq)
@@ -77,6 +83,81 @@ func (c *SaasClient) TaskUpload(sha256 string, file *os.File, offset int64, size
return c.upload(postUrl, file, offset, size)
}
func (c *SaasClient) TaskDownload(sha256 string, file *os.File, offset int64, size int) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.TaskDownloadPath, "sha256", sha256)
return c.download(postUrl, file, offset, size)
}
func (c *SaasClient) TargetList(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.TargetListPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) TargetCreate(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.TargetCreatePath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) TargetDelete(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.TargetDeletePath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) BindSet(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.BindSetPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) BindDelete(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.BindDeletePath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) ScriptRun(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ScriptRunPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) ExpList(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ExpListPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) ExpGet(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ExpGetPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) GrantList(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.GrantListPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) GrantAdd(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.GrantAddPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) GrantDelete(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.GrantDeletePath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) ExpGrantList(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ExpGrantListPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) ExpGrantAdd(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ExpGrantAddPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) ExpGrantDelete(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ExpGrantDeletePath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) makeUrl(baseUrl, path string, params ...string) string {
url, err := url.Parse(baseUrl)
if err != nil {
@@ -232,3 +313,111 @@ func (c *SaasClient) upload(url string, file *os.File, offset int64, size int) (
return saasRes, nil
}
func (c *SaasClient) download(url string, file *os.File, offset int64, size int) (saasRes *saasapi.SaasRes, err error) {
if file == nil {
return nil, fmt.Errorf("file is nil")
}
if size <= 0 {
return nil, fmt.Errorf("size is invalid")
}
req, err := http.NewRequest("GET", url, bytes.NewBuffer([]byte{}))
if err != nil {
fmt.Println("http new request error", err)
return nil, err
}
timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
md5byte := md5.Sum([]byte(c.Auth.Account + c.Auth.Token + timeStamp))
authorization := hex.EncodeToString(md5byte[:])
req.Header.Add("Account", c.Auth.Account)
req.Header.Add("Time", timeStamp)
req.Header.Add("Authorization", authorization)
req.Header.Add("Accept-Encoding", "gzip")
res, err := c.Client.Do(req)
if err != nil {
fmt.Println("http send error", err)
return nil, err
}
defer res.Body.Close()
if res.StatusCode != 200 {
err = fmt.Errorf("NOT 200. %v", res.StatusCode)
fmt.Println("http state error", err)
return nil, err
}
bodyReader := res.Body
if strings.Contains(res.Header.Get("Content-Encoding"), "gzip") {
gz, err := gzip.NewReader(res.Body)
if err != nil {
fmt.Println("gzip newreader error", err)
return nil, err
}
defer gz.Close()
bodyReader = gz
}
resBody, err := io.ReadAll(bodyReader)
if err != nil {
fmt.Println("read body error", err)
return nil, err
}
saasRes = &saasapi.SaasRes{}
if strings.Contains(res.Header.Get("Content-Type"), "application/octet-stream") {
if len(resBody) == size {
file.WriteAt(resBody, offset)
} else {
err = fmt.Errorf("body size error. body:%v, want:%v", len(resBody), size)
fmt.Println("http read body error", err)
return nil, err
}
} else {
if c.ResponseEncoder == RESPONSE_ENCODER_PROTOBUF {
err = proto.Unmarshal(resBody, saasRes)
if err != nil {
fmt.Println("unmarshal response body to protobuf error", err)
return nil, err
}
} else {
err = json.Unmarshal(resBody, saasRes)
if err != nil {
fmt.Println("unmarshal response body to json error", err)
return nil, err
}
}
}
return saasRes, nil
}
func (c *SaasClient) ScriptCreate(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ScriptCreatePath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) ScriptList(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ScriptListPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) ScriptDelete(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ScriptDeletePath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) ScriptGet(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ScriptGetPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) ScriptUse(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ScriptUsePath)
return c.post(postUrl, saasReq)
}