Compare commits

36 Commits

Author SHA1 Message Date
algotao
232a2c9d2e 更新docker版本 2026-01-19 14:56:22 +08:00
algotao
5cf860acfb 支持ds重置(当前限geo) 2026-01-19 14:54:18 +08:00
algotao
369023b81d 优化error输出 2026-01-11 17:24:11 +08:00
algotao
5e102ea8e7 script run调整为script debug;优化错误信息输出 2026-01-11 17:23:51 +08:00
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
63 changed files with 7881 additions and 516 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,5 @@
vendor/ vendor/
*.out *.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"
}
}

4227
cmd.pb.go

File diff suppressed because it is too large Load Diff

414
cmd.proto
View File

@@ -2,23 +2,55 @@ syntax = "proto3";
package saasapi; package saasapi;
option go_package = "e.coding.net/rta/public/saasapi"; option go_package = "git.algo.com.cn/public/saasapi";
// SaasReq 命令请求 // SaasReq 命令请求
message SaasReq { message SaasReq {
oneof cmd { oneof cmd {
Info info = 5; // 获取账号设置
Read read = 10; // 批量读取 Read read = 10; // 批量读取
Write write = 11; // 批量写入 Write write = 11; // 批量写入
ColumnWrite column_write = 12; // 全量列式写入 ColumnWrite column_write = 12; // 全量列式写入
ResetDs reset_ds = 13; // 清空数据区
Task task_create = 20; // 任务创建 Task task_create = 20; // 任务创建
TaskList task_list = 21; // 列出任务 TaskList task_list = 21; // 列出任务
TaskRun task_run = 22; // 执行任务 TaskRun task_run = 22; // 执行任务
TaskDelete task_delete = 23; // 删除任务 TaskDelete task_delete = 23; // 删除任务
TaskInfo task_info = 24; // 任务详情 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; // 删除数据授权
ScriptDebug script_debug = 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 批量读取命令 // Read 批量读取命令
message Read { message Read {
string dataspace_id = 1; // 数据空间ID string dataspace_id = 1; // 数据空间ID
@@ -42,29 +74,30 @@ message Write {
// WriteItem 写入命令 // WriteItem 写入命令
message WriteItem { message WriteItem {
string userid = 1; // 用户ID string userid = 1; // 用户ID
Bytes write_bytes = 2; // byte区域 Bytes write_bytes = 2 [deprecated = true]; // byte区域。!!!弃用请使用bytes_kv
Uint32s write_uint32s = 3; // uint32区域 Uint32s write_uint32s = 3 [deprecated = true]; // uint32区域。!!!弃用请使用uint32s_kv
FlagsWithExpire write_flags_with_expire = 4; // 标志位区域 FlagsWithExpire write_flags_with_expire = 4 [deprecated = true]; // 标志位区域。!!!弃用请使用flags_with_expire_kv
map<uint32, uint32> bytes_kv = 5; // 写入uint8key为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区域 // Bytes 写入uint8区域
message Bytes { message Bytes {
bytes bytes = 1; // 写入的byte bytes bytes = 1; // 写入的uint8
uint64 index_1 = 2; // 写入byte的索引值(0..63) uint64 index_1 = 2; // 写入uint8的索引值(0..63)
uint64 index_2 = 3; // 写入byte的索引值(64..127)
} }
// Uint32s 写入uint32区域 // Uint32s 写入uint32区域
message Uint32s { message Uint32s {
repeated uint32 uint32s = 1; // 写入的uint32 repeated uint32 uint32s = 1; // 写入的uint32
uint64 index_1 = 2; // 写入uint32的索引值(0..15) 最多 16 uint64 index_1 = 2; // 写入uint32的索引值(0..7) 最多 8
//uint64 index_2 = 3; // 写入uint32的索引值(当前不支持)
} }
// FlagsWithExpire 写入标志位区域 // FlagsWithExpire 写入标志位区域
message FlagsWithExpire { message FlagsWithExpire {
repeated FlagWithExpire flags_with_expire = 1; // 写入的标志位 repeated FlagWithExpire flags_with_expire = 1; // 写入的标志位
uint64 index_1 = 2; // 写入标志位的索引值 uint64 index_1 = 2; // 写入标志位的索引值(0..3) 最多 4 个
} }
// FlagWithExpire 标志位 // FlagWithExpire 标志位
@@ -83,18 +116,27 @@ message ColumnWrite {
FlagsWithExpire write_flags_with_expire = 5; // 标志位区域 FlagsWithExpire write_flags_with_expire = 5; // 标志位区域
} }
// ResetDs 清空数据区命令
message ResetDs {
string dataspace_id = 1; // 数据空间ID
}
message Task { message Task {
string dataspace_id = 1; // 数据空间ID string dataspace_id = 1; // 数据空间ID
string appid = 2; // 小程序/小游戏/公众号/视频号的appid string appid = 2; // 小程序/小游戏/公众号/视频号的appid
string task_sha256 = 3; // 任务sha256 string task_sha256 = 3; // 任务sha256
string task_description = 4; // 任务描述 string task_description = 4; // 任务描述
repeated FileInfo task_file_infos = 5; // 文件列表 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 create_time = 10; // 创建时间
string run_time = 11; // 运行时间 string run_time = 11; // 运行时间
string finish_time = 12; // 完成时间 string finish_time = 12; // 完成时间
uint32 running_block = 13; // 正在运行的块编号
uint32 total_block = 14; // 总块数
TaskStatus status = 15; // 任务状态 TaskStatus status = 15; // 任务状态
} }
@@ -119,40 +161,191 @@ message TaskInfo {
string task_sha256 = 1; // 任务sha256 string task_sha256 = 1; // 任务sha256
} }
// FileInfo 任务文件信息
message FileInfo { message FileInfo {
string file_name = 1; // 文件名 string file_name = 1; // 文件名
uint64 file_size = 2; // 文件大小 uint64 file_size = 2; // 文件大小
repeated FileBlock file_blocks = 3; // 文件块列表 repeated FileBlock file_blocks = 3; // 文件块列表
} }
// FileBlock 文件块信息
message FileBlock { message FileBlock {
string block_sha256 = 1; // 块的sha256 string block_sha256 = 1; // 块的sha256
uint64 block_length = 2; // 块的字节长度 uint64 block_length = 2; // 块的字节长度
bool uploaded = 3; // 是否已上传在TaskCreate/TaskInfo请求返回 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数字型
}
// ScriptDebug 调试脚本
message ScriptDebug {
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 命令返回 // SaasRes 命令返回
message SaasRes { message SaasRes {
ErrorCode code = 1; // 返回码 ErrorCode code = 1; // 返回码
string status = 2; // 返回信息的文本提示 string status = 2; // 返回信息的文本提示
oneof res { oneof res {
InfoRes info_res = 5; // 账号信息返回
ReadRes read_res = 10; // 读取命令返回 ReadRes read_res = 10; // 读取命令返回
WriteRes write_res = 11; // 写入命令返回 WriteRes write_res = 11; // 写入命令返回
ResetDsRes reset_ds_res = 13; // 清空数据区命令返回
Task task_create_res = 20; // 创建任务返回状态 Task task_create_res = 20; // 创建任务返回状态
TaskListRes task_list_res = 21; // 任务列表返回状态 TaskListRes task_list_res = 21; // 任务列表返回状态
Task task_run_res = 22; // 运行任务返回状态 Task task_run_res = 22; // 运行任务返回状态
Task task_delete_res = 23; // 删除任务返回状态 Task task_delete_res = 23; // 删除任务返回状态
Task task_info_res = 24; // 任务详情返回状态 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; // 删除数据授权返回状态
ScriptDebugRes script_debug_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区
repeated string geoip = 8; // GEOIP区
repeated string geofac = 9; // GEOFAC区(经常活动城市)
}
// InfoRes 账号信息返回
message InfoRes {
DataSpace dataspace = 1; // 可用数据区列表
repeated string target_id = 2; // 策略ID列表
}
// ReadRes 读记录返回
message ReadRes { message ReadRes {
uint32 succ_cmd_count = 1; // 成功的命令数量 uint32 succ_cmd_count = 1; // 成功的命令数量
uint32 fail_cmd_count = 2; // 失败的命令数量 uint32 fail_cmd_count = 2; // 失败的命令数量
repeated ValueItem cmd_res = 3 ; // 返回的命令 repeated ValueItem cmd_res = 3 ; // 返回的命令
} }
// WriteRes 写记录返回
message WriteRes { message WriteRes {
//uint32 succ_cmd_count = 1; // 成功的命令数量 //uint32 succ_cmd_count = 1; // 成功的命令数量
//uint32 fail_cmd_count = 2; // 失败的命令数量 //uint32 fail_cmd_count = 2; // 失败的命令数量
@@ -163,23 +356,193 @@ message WriteRes {
message ValueItem { message ValueItem {
uint32 cmd_index = 1; // 命令索引 uint32 cmd_index = 1; // 命令索引
CmdErrorCode cmd_code = 2; // 状态 CmdErrorCode cmd_code = 2; // 状态
bytes bytes = 3; // byte区域 bytes bytes = 3 [deprecated = true]; // byte区域。!!!弃用
repeated uint32 uint32s = 4; // uint32区域 repeated uint32 uint32s = 4 [deprecated = true]; // uint32区域。!!!弃用
repeated FlagWithExpire flags_with_expire = 5; // 标志位区域 repeated FlagWithExpire flags_with_expire = 5 [deprecated = true]; // 标志位区域。!!!弃用
uint32 last_modify_time = 6; // 最后修改时间 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; // 标志位区域
} }
// ResetDsRes 清空数据区返回
message ResetDsRes {
string dataspace_id = 1; // 数据空间ID
}
// TaskListRes 任务列表返回
message TaskListRes { message TaskListRes {
repeated Task tasks = 1; // 任务列表 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; // 向外授权列表
}
// ScriptDebugRes 调试脚本返回
message ScriptDebugRes {
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 返回码 // ErrorCode 返回码
enum ErrorCode { enum ErrorCode {
SUCC = 0; // 成功 SUCC = 0; // 成功
INVALID_ACCOUNT = 101; // Account不合法 INVALID_ACCOUNT = 101; // Account不合法
INVALID_TIMESTAMP = 102; // 头信息缺少时间戳或不正确 INVALID_TIMESTAMP = 102; // 头信息缺少时间戳或不正确
INVALID_SIGNATURE = 103; // 头信息缺少签名 INVALID_SIGNATURE = 103; // 头信息缺少签名
AUTH_FAIL = 104; // 签名验失败 AUTH_FAIL = 104; // 签名验失败
DISABLED_ACCOUNT = 105; // 账号已禁用 DISABLED_ACCOUNT = 105; // 账号已禁用
INVALID_CONTENT_TYPE = 110; // 非法的Content-Type INVALID_CONTENT_TYPE = 110; // 非法的Content-Type
READ_BODY = 111; // 读取 http body 失败 READ_BODY = 111; // 读取 http body 失败
@@ -204,12 +567,17 @@ enum ErrorCode {
DATA_ERROR = 201; // 数据错误 DATA_ERROR = 201; // 数据错误
CMD_ERROR = 202; // 命令行执行错误 CMD_ERROR = 202; // 命令行执行错误
API_ERROR = 301; // 调用内部API错误
PARAM_ERROR = 401; // 参数错误
} }
enum CmdErrorCode { enum CmdErrorCode {
OK = 0; // 成功 OK = 0; // 成功
} }
// TaskStatus 任务状态
enum TaskStatus { enum TaskStatus {
ALL = 0; // 全部 ALL = 0; // 全部
WAITING = 1; // 等待中 WAITING = 1; // 等待中
@@ -221,3 +589,17 @@ enum TaskStatus {
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/ debug/
saastool saastool
saastool_linux saastool_linux
cfg.toml *.toml
test/
*.lua
test.txt

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

@@ -0,0 +1,42 @@
package main
import (
"fmt"
"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:
return fmt.Errorf(`Unknown command "%s"`+"\n"+`Run 'saastool bind help' for usage`, name)
}
}
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.
`

View File

@@ -0,0 +1,98 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", 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 {
return fmt.Errorf("Id parse error. value: %v. %w", v, err)
}
numIds = append(numIds, n)
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
bindRes := res.GetBindDeleteRes()
fmt.Printf("bind res: %v\n", protojson.Format(bindRes))
return nil
}

View File

@@ -0,0 +1,98 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", 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 {
return fmt.Errorf("Account parse error. value: %v. %w", v, err)
}
numAccounts = append(numAccounts, n)
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
fmt.Printf("bind res: %v\n", protojson.Format(res.GetBindSetRes()))
return nil
}

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

@@ -0,0 +1,101 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", 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 {
return fmt.Errorf("AD parse error. value: %v. %w", v, err)
}
numAds = append(numAds, n)
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
fmt.Printf("bind res: %v\n", protojson.Format(res.GetBindSetRes()))
return nil
}

View File

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

View File

@@ -11,7 +11,7 @@ import (
"strings" "strings"
"sync" "sync"
"e.coding.net/rta/public/saasapi" "git.algo.com.cn/public/saasapi"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
) )
@@ -38,8 +38,7 @@ func RunConvert(args ...string) error {
destPath := paramDestPath(fs) destPath := paramDestPath(fs)
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err) return fmt.Errorf("Command line parse error: %w", err)
return err
} }
if fs.NArg() > 0 || *mapCfgFile == "" || len(*sourcePath) == 0 || len(*destPath) == 0 { if fs.NArg() > 0 || *mapCfgFile == "" || len(*sourcePath) == 0 || len(*destPath) == 0 {
@@ -49,8 +48,7 @@ func RunConvert(args ...string) error {
mapCfg, err := LoadMapFile(*mapCfgFile) mapCfg, err := LoadMapFile(*mapCfgFile)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err) return fmt.Errorf("LoadMapFile error: %w", err)
return err
} }
convertParams := convertParams{ convertParams := convertParams{
@@ -236,11 +234,7 @@ func convertBatch(lines []string, convertParams convertParams, resultChan chan<-
saasWriteItem.WriteBytes = &saasapi.Bytes{} saasWriteItem.WriteBytes = &saasapi.Bytes{}
} }
saasWriteItem.WriteBytes.Bytes = append(saasWriteItem.WriteBytes.Bytes, *targetinfo.WriteByte) saasWriteItem.WriteBytes.Bytes = append(saasWriteItem.WriteBytes.Bytes, *targetinfo.WriteByte)
if targetinfo.WriteBytePos < 64 {
saasWriteItem.WriteBytes.Index_1 |= 1 << targetinfo.WriteBytePos saasWriteItem.WriteBytes.Index_1 |= 1 << targetinfo.WriteBytePos
} else if targetinfo.WriteBytePos < 128 {
saasWriteItem.WriteBytes.Index_2 |= 1 << (targetinfo.WriteBytePos - 64)
}
} }
if targetinfo.WriteUint32 != nil { 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
}

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

@@ -0,0 +1,376 @@
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:
return fmt.Errorf("SRTA_ENV is not demo or prd")
}
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", "geoip", "geofac":
default:
return nil, fmt.Errorf("ds must use did/wuid/geo/geoip/geofac. 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
}

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

@@ -0,0 +1,42 @@
package main
import (
"fmt"
"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:
return fmt.Errorf(`Unknown command "%s"`+"\n"+`Run 'saastool exp help' for usage`, name)
}
}
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.
`

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

@@ -0,0 +1,168 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", 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 {
return fmt.Errorf("Expid parse error. value: %v. %w", id, err)
}
if idNum == 0 || idNum > 10 {
return fmt.Errorf("Expid range error.")
}
bucketIDsNumSlice = append(bucketIDsNumSlice, uint32(idNum))
}
}
if *beginDay < 20250101 || *beginDay > 21001231 || *endDay < 20250101 || *endDay > 21001231 {
fs.PrintDefaults()
return fmt.Errorf("Begin/End day error.")
}
if *target == "" {
fs.PrintDefaults()
return fmt.Errorf("Target error.")
}
uidNumSlice := []uint64{}
if *advertiserIDs != "" {
uidSlice := strings.Split(*advertiserIDs, ",")
for _, id := range uidSlice {
idNum, err := strconv.ParseUint(id, 10, 64)
if err != nil {
return fmt.Errorf("Advertiser id parse error. value: %v. %w", id, err)
}
if idNum == 0 {
return fmt.Errorf("Advertiser id error.")
}
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] {
return fmt.Errorf("Group by error. group: %v", group)
}
}
}
extFieldsSlice := []string{}
if *extFields != "" {
extFieldsSlice = strings.Split(*extFields, ",")
if slices.Contains(extFieldsSlice, "") {
return fmt.Errorf("Ext field error.")
}
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
getExpRes := res.GetExpGetRes()
fmt.Printf("exp res: %v\n", protojson.Format(getExpRes))
return nil
}

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

@@ -0,0 +1,37 @@
package main
import (
"fmt"
"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:
return fmt.Errorf(`Unknown command "%s"`+"\n"+`Run 'saastool exp grant help' for usage`, name)
}
}
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,75 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 {
fs.PrintDefaults()
return nil
}
if *srtaAccountId == 0 {
fs.PrintDefaults()
return fmt.Errorf("sRTA account ID is required")
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
expGrantRes := res.GetExpGrantAddRes()
fmt.Printf("exp grant add res: %v\n", protojson.Format(expGrantRes))
return nil
}

View File

@@ -0,0 +1,75 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 {
fs.PrintDefaults()
return nil
}
if *srtaAccountId == 0 {
fs.PrintDefaults()
return fmt.Errorf("sRTA account ID is required")
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
expGrantRes := res.GetExpGrantDeleteRes()
fmt.Printf("exp grant delete res: %v\n", protojson.Format(expGrantRes))
return nil
}

View File

@@ -0,0 +1,65 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
expGrantRes := res.GetExpGrantListRes()
fmt.Printf("exp grant list res: %v\n", protojson.Format(expGrantRes))
return nil
}

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

@@ -0,0 +1,65 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
listExpRes := res.GetExpListRes()
fmt.Printf("exp res: %v\n", protojson.Format(listExpRes))
return nil
}

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

@@ -0,0 +1,42 @@
package main
import (
"fmt"
"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:
return fmt.Errorf(`Unknown command "%s"`+"\n"+`Run 'saastool grant help' for usage`, name)
}
}
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.
`

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

@@ -0,0 +1,93 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 {
fs.PrintDefaults()
return nil
}
if *srtaAccountId == 0 {
fs.PrintDefaults()
return fmt.Errorf("sRTA account ID is required.")
}
if *grantIndex == "" {
fs.PrintDefaults()
return fmt.Errorf("Grant index is required.")
}
if *dsid == 0 {
fs.PrintDefaults()
return fmt.Errorf("Data space ID is required.")
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
grantRes := res.GetGrantAddRes()
fmt.Printf("grant add res: %v\n", protojson.Format(grantRes))
return nil
}

View File

@@ -0,0 +1,93 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 {
fs.PrintDefaults()
return nil
}
if *dsid == 0 {
fs.PrintDefaults()
return fmt.Errorf("data space ID is required.")
}
if *srtaAccountId == 0 {
fs.PrintDefaults()
return fmt.Errorf("sRTA account ID is required.")
}
if *grantIndex == "" {
fs.PrintDefaults()
return fmt.Errorf("grant index is required.")
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
grantRes := res.GetGrantDeleteRes()
fmt.Printf("grant delete res: %v\n", protojson.Format(grantRes))
return nil
}

View File

@@ -0,0 +1,65 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
grantRes := res.GetGrantListRes()
fmt.Printf("grant list res: %v\n", protojson.Format(grantRes))
return nil
}

View File

@@ -15,13 +15,22 @@ const usage = `
Usage: saastool COMMAND [OPTIONS] Usage: saastool COMMAND [OPTIONS]
Commands: Commands:
info Saas Info
write Write user's 'bytes / uint32s / flags' write Write user's 'bytes / uint32s / flags'
read Read user's 'bytes / uint32s / flags' read Read user's 'bytes / uint32s / flags'
columnwrite Write columns for 'deviceid / openid' users columnwrite Write columns for 'deviceid / openid' users
resetds Reset data space
convert Convert data to write format 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. "help" is the default command.

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

@@ -0,0 +1,65 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
infoRes := res.GetInfoRes()
fmt.Printf("Info res: %v\n", protojson.Format(infoRes))
return nil
}

View File

@@ -7,6 +7,7 @@ import (
func main() { func main() {
if err := Run(os.Args[1:]...); err != nil { if err := Run(os.Args[1:]...); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)
} }
} }
@@ -18,21 +19,35 @@ func Run(args ...string) error {
switch name { switch name {
case "", "help": case "", "help":
return RunHelp(args...) return RunHelp(args...)
case "info":
return RunInfo(args...)
case "write": case "write":
return RunWrite(args...) return RunWrite(args...)
case "read": case "read":
return RunRead(args...) return RunRead(args...)
case "columnwrite": case "columnwrite":
return RunColumnWrite(args...) return RunColumnWrite(args...)
case "resetds":
return RunResetDs(args...)
case "convert": case "convert":
return RunConvert(args...) return RunConvert(args...)
case "verify": case "verify":
return RunVerify(args...) return RunVerify(args...)
case "task": case "task":
return RunTask(args...) 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: default:
err := fmt.Errorf(`unknown command "%v"`+"\n"+`Run 'saastool help' for usage`, name) return fmt.Errorf(`Unknown command "%v"`+"\n"+`Run 'saastool help' for usage`, name)
fmt.Fprintln(os.Stderr, err.Error())
return err
} }
} }

View File

@@ -62,7 +62,7 @@ func paramBatchSize(fs *flag.FlagSet) *uint {
} }
func paramBlockSize(fs *flag.FlagSet) *string { 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 { func paramClear(fs *flag.FlagSet) *bool {
@@ -73,6 +73,98 @@ func paramDataSpaceId(fs *flag.FlagSet) *string {
return fs.String("ds", "", "Data space ID") 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 解析字节大小字符串为字节数 // ParseByteSize 解析字节大小字符串为字节数
func ParseByteSize(sizeStr string) (uint64, error) { func ParseByteSize(sizeStr string) (uint64, error) {
sizeStr = strings.TrimSpace(sizeStr) sizeStr = strings.TrimSpace(sizeStr)

View File

@@ -4,11 +4,10 @@ import (
"flag" "flag"
"fmt" "fmt"
"net/http" "net/http"
"os"
"strings" "strings"
"e.coding.net/rta/public/saasapi" "git.algo.com.cn/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp" "git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
) )
@@ -32,8 +31,7 @@ func RunRead(args ...string) error {
userids := paramUserids(fs) userids := paramUserids(fs)
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err) return fmt.Errorf("Command line parse error: %w", err)
return err
} }
// 切割字符串 // 切割字符串
@@ -44,15 +42,13 @@ func RunRead(args ...string) error {
return nil return nil
} }
if strings.ToLower(*ds) == "openid" && len(*appid) == 0 { if strings.ToLower(*ds) == "wuid" && len(*appid) == 0 {
fmt.Fprintln(os.Stderr, "appid must be set when data space is openid") return fmt.Errorf("Appid must be set when data space is wuid.")
return nil
} }
cfg, err := LoadConfigFile(*cfgFile) cfg, err := LoadConfigFile(*cfgFile)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "load config file error", "err", err) return fmt.Errorf("LoadConfigFile error: %w", err)
return err
} }
readParams := readParams{ readParams := readParams{
@@ -62,7 +58,7 @@ func RunRead(args ...string) error {
ds: *ds, ds: *ds,
saasHttp: &saashttp.SaasClient{ saasHttp: &saashttp.SaasClient{
Client: &http.Client{}, Client: &http.Client{},
ApiUrls: &cfg.ApiUrls, ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth, Auth: &cfg.Auth,
}, },
} }
@@ -92,18 +88,16 @@ func doRead(readParams readParams) error {
read.ReadItems = saasReadItems read.ReadItems = saasReadItems
res, err := readParams.saasHttp.Read(saasReq) res, err := readParams.saasHttp.Read(saasReq)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "submit read error", "err", err) return fmt.Errorf("Submit Command error: %w", err)
return err
} }
if res.GetCode() != saasapi.ErrorCode_SUCC { if res.GetCode() != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, protojson.Format(res)) return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
return err
} else {
fmt.Println(protojson.Format(res))
} }
readRes := res.GetReadRes()
fmt.Printf("read res: %v\n", protojson.Format(readRes))
return nil return nil
} }

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

@@ -0,0 +1,71 @@
package main
import (
"flag"
"fmt"
"net/http"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson"
)
type resetDsParams struct {
ds string
saasHttp *saashttp.SaasClient
}
func RunResetDs(args ...string) error {
fs := flag.NewFlagSet("resetds", flag.ExitOnError)
cfgFile := paramConfig(fs)
ds := paramDataSpaceId(fs)
if err := fs.Parse(args); err != nil {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 || len(*ds) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", err)
}
resetDsParams := resetDsParams{
ds: *ds,
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doResetDs(resetDsParams)
}
func doResetDs(resetDsParams resetDsParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ResetDs{
ResetDs: &saasapi.ResetDs{
DataspaceId: resetDsParams.ds,
},
},
}
res, err := resetDsParams.saasHttp.ResetDS(saasReq)
if err != nil {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
resetRes := res.GetResetDsRes()
fmt.Printf("ResetDS res: %v\n", protojson.Format(resetRes))
return nil
}

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

@@ -0,0 +1,51 @@
package main
import (
"fmt"
"strings"
)
func RunScript(args ...string) error {
name, args := ParseCommandName(args)
// 从参数中解析出命令
switch name {
case "", "help":
return RunScriptHelp(args...)
case "debug", "run":
return RunScriptDebug(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:
return fmt.Errorf(`Unknown command "%s"`+"\n"+`Run 'saastool script help' for usage`, name)
}
}
func RunScriptHelp(args ...string) error {
fmt.Println(strings.TrimSpace(scriptUsage))
return nil
}
const scriptUsage = `
Usage: saastool script COMMAND [OPTIONS]
Commands:
debug Debug lua script 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,88 @@
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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 || len(*luaFile) == 0 || len(*luaName) == 0 {
fs.PrintDefaults()
return nil
}
file, err := os.Open(*luaFile)
if err != nil {
return fmt.Errorf("Lua file open error: %w", err)
}
defer file.Close()
body, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("Lua file read error: %w", err)
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
scriptRes := res.GetScriptCreateRes()
fmt.Printf("script res: %v\n", protojson.Format(scriptRes))
return nil
}

View File

@@ -0,0 +1,105 @@
package main
import (
"flag"
"fmt"
"io"
"net/http"
"os"
"git.algo.com.cn/public/saasapi"
"git.algo.com.cn/public/saasapi/pkg/saashttp"
)
type scriptDebugParams struct {
luaScript string
did string
os saasapi.OS
saasHttp *saashttp.SaasClient
}
func RunScriptDebug(args ...string) error {
fs := flag.NewFlagSet("debug", flag.ExitOnError)
cfgFile := paramConfig(fs)
luaFile := paramLua(fs)
did := paramDid(fs)
tos := paramOS(fs)
if err := fs.Parse(args); err != nil {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 || len(*luaFile) == 0 || len(*did) == 0 {
fs.PrintDefaults()
return nil
}
if !(*tos == 1 || *tos == 2 || *tos == 7) {
fs.PrintDefaults()
return nil
}
file, err := os.Open(*luaFile)
if err != nil {
return fmt.Errorf("Lua file open error: %w", err)
}
defer file.Close()
body, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("Lua file read error: %w", err)
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", err)
}
scriptDebugParams := scriptDebugParams{
luaScript: string(body),
did: *did,
os: saasapi.OS(*tos),
saasHttp: &saashttp.SaasClient{
Client: &http.Client{},
ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth,
},
}
return doScriptDebug(scriptDebugParams)
}
func doScriptDebug(scriptDebugParams scriptDebugParams) error {
saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_ScriptDebug{
ScriptDebug: &saasapi.ScriptDebug{
LuaScript: scriptDebugParams.luaScript,
ServerDid: scriptDebugParams.did,
Os: scriptDebugParams.os,
},
},
}
res, err := scriptDebugParams.saasHttp.ScriptDebug(saasReq)
if err != nil {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
scriptDebugRes := res.GetScriptDebugRes()
fmt.Println("ERROROUT_OUTPUT:")
fmt.Print(scriptDebugRes.GetErrorOutput())
fmt.Println()
fmt.Println("PRINT_OUTPUT:")
fmt.Print(scriptDebugRes.GetPrintOutput())
fmt.Println()
fmt.Println("DATASPACE_OUTPUT:")
fmt.Print(scriptDebugRes.GetDataspaceOut())
fmt.Println()
fmt.Println("TARGETS_OUTPUT:")
fmt.Print(scriptDebugRes.GetTargetsOutput())
return nil
}

View File

@@ -0,0 +1,71 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 || len(*luaName) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
scriptRes := res.GetScriptDeleteRes()
fmt.Printf("script res: %v\n", protojson.Format(scriptRes))
return nil
}

View File

@@ -0,0 +1,71 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 || len(*luaName) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
scriptRes := res.GetScriptGetRes()
fmt.Printf("script res: %v\n", protojson.Format(scriptRes))
return nil
}

View File

@@ -0,0 +1,66 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
scriptRes := res.GetScriptListRes()
fmt.Printf("script res: %v\n", protojson.Format(scriptRes))
return nil
}

View File

@@ -0,0 +1,71 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 || len(*luaName) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
scriptRes := res.GetScriptUseRes()
fmt.Printf("script use res: %v\n", protojson.Format(scriptRes))
return nil
}

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

@@ -0,0 +1,42 @@
package main
import (
"fmt"
"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:
return fmt.Errorf(`Unknown command "%s"`+"\n"+`Run 'saastool target help' for usage`, name)
}
}
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,75 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 || len(*targetId) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
targetRes := res.GetTargetCreateRes()
fmt.Printf("target res: %v\n", protojson.Format(targetRes))
return nil
}

View File

@@ -0,0 +1,70 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 || len(*targetId) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
targetDeleteRes := res.GetTargetDeleteRes()
fmt.Printf("target res: %v\n", protojson.Format(targetDeleteRes))
return nil
}

View File

@@ -0,0 +1,82 @@
package main
import (
"flag"
"fmt"
"net/http"
"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 {
return fmt.Errorf("Command line parse error: %w", 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 {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("Submit Command error: %w", err)
}
if res.Code != saasapi.ErrorCode_SUCC {
return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
}
targetRes := res.GetTargetListRes()
fmt.Printf("target res: %v\n", protojson.Format(targetRes))
return nil
}

View File

@@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"os"
"strings" "strings"
) )
@@ -25,13 +24,12 @@ func RunTask(args ...string) error {
return RunTaskInfo(args...) return RunTaskInfo(args...)
case "upload": case "upload":
return RunTaskUpload(args...) return RunTaskUpload(args...)
case "download":
return RunTaskDownload(args...)
case "run": case "run":
return RunTaskRun(args...) return RunTaskRun(args...)
default: default:
err := fmt.Errorf(`unknown command "%s"`+"\n"+`Run 'saastool task help' for usage`, name) return fmt.Errorf(`Unknown command "%s"`+"\n"+`Run 'saastool task help' for usage`, name)
fmt.Fprintln(os.Stderr, err)
return err
} }
} }
@@ -51,6 +49,7 @@ Commands:
delete Delete a task on server delete Delete a task on server
info Get a task info on server info Get a task info on server
upload Upload task's file block to server upload Upload task's file block to server
download Download task's file block to local
"help" is the default command. "help" is the default command.

View File

@@ -6,8 +6,8 @@ import (
"net/http" "net/http"
"os" "os"
"e.coding.net/rta/public/saasapi" "git.algo.com.cn/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp" "git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
) )
@@ -23,8 +23,7 @@ func RunTaskCreate(args ...string) error {
hashFile := paramInputHashFile(fs) hashFile := paramInputHashFile(fs)
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err) return fmt.Errorf("Command line parse error: %w", err)
return err
} }
if fs.NArg() > 0 || len(*hashFile) == 0 { if fs.NArg() > 0 || len(*hashFile) == 0 {
@@ -34,15 +33,14 @@ func RunTaskCreate(args ...string) error {
cfg, err := LoadConfigFile(*cfgFile) cfg, err := LoadConfigFile(*cfgFile)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err) return fmt.Errorf("LoadConfigFile error: %w", err)
return err
} }
createTaskParams := createTaskParams{ createTaskParams := createTaskParams{
hashFile: *hashFile, hashFile: *hashFile,
saasHttp: &saashttp.SaasClient{ saasHttp: &saashttp.SaasClient{
Client: &http.Client{}, Client: &http.Client{},
ApiUrls: &cfg.ApiUrls, ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth, Auth: &cfg.Auth,
}, },
task: &saasapi.Task{}, task: &saasapi.Task{},
@@ -50,12 +48,11 @@ func RunTaskCreate(args ...string) error {
taskBuf, err := os.ReadFile(createTaskParams.hashFile) taskBuf, err := os.ReadFile(createTaskParams.hashFile)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "open task file error", "err", err) return fmt.Errorf("open task file error: %w", err)
return err
} }
if err = protojson.Unmarshal(taskBuf, createTaskParams.task); err != nil { if err = protojson.Unmarshal(taskBuf, createTaskParams.task); err != nil {
fmt.Fprintln(os.Stderr, "parse task file error", "err", err) return fmt.Errorf("parse task file error: %w", err)
} }
return doTaskCreate(createTaskParams) return doTaskCreate(createTaskParams)
@@ -69,15 +66,12 @@ func doTaskCreate(createTaskParams createTaskParams) error {
} }
res, err := createTaskParams.saasHttp.TaskCreate(saasReq) res, err := createTaskParams.saasHttp.TaskCreate(saasReq)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "submit Create Task error", "err", err) return fmt.Errorf("Submit Command error: %w", err)
return err
} }
if res.Code != saasapi.ErrorCode_SUCC { if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "task create failed", "code", res.Code, "status", res.Status) return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
return nil
} }
taskRes := res.GetTaskCreateRes() taskRes := res.GetTaskCreateRes()

View File

@@ -4,10 +4,9 @@ import (
"flag" "flag"
"fmt" "fmt"
"net/http" "net/http"
"os"
"e.coding.net/rta/public/saasapi" "git.algo.com.cn/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp" "git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
) )
@@ -22,8 +21,7 @@ func RunTaskDelete(args ...string) error {
sha256 := paramSha256(fs) sha256 := paramSha256(fs)
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err) return fmt.Errorf("Command line parse error: %w", err)
return err
} }
if fs.NArg() > 0 || len(*sha256) == 0 { if fs.NArg() > 0 || len(*sha256) == 0 {
@@ -33,28 +31,23 @@ func RunTaskDelete(args ...string) error {
cfg, err := LoadConfigFile(*cfgFile) cfg, err := LoadConfigFile(*cfgFile)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err) return fmt.Errorf("LoadConfigFile error: %w", err)
return err
} }
deleteTaskParams := deleteTaskParams{ deleteTaskParams := deleteTaskParams{
taskSha256: *sha256, taskSha256: *sha256,
saasHttp: &saashttp.SaasClient{ saasHttp: &saashttp.SaasClient{
Client: &http.Client{}, Client: &http.Client{},
ApiUrls: &cfg.ApiUrls, ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth, Auth: &cfg.Auth,
}, },
} }
taskRes, err := doTaskDelete(deleteTaskParams) return doTaskDelete(deleteTaskParams)
if err != nil {
fmt.Printf("task res: %v\n", protojson.Format(taskRes))
}
return err
} }
func doTaskDelete(deleteTaskParams deleteTaskParams) (*saasapi.Task, error) { func doTaskDelete(deleteTaskParams deleteTaskParams) error {
saasReq := &saasapi.SaasReq{ saasReq := &saasapi.SaasReq{
Cmd: &saasapi.SaasReq_TaskDelete{ Cmd: &saasapi.SaasReq_TaskDelete{
TaskDelete: &saasapi.TaskDelete{ TaskDelete: &saasapi.TaskDelete{
@@ -65,17 +58,14 @@ func doTaskDelete(deleteTaskParams deleteTaskParams) (*saasapi.Task, error) {
res, err := deleteTaskParams.saasHttp.TaskDelete(saasReq) res, err := deleteTaskParams.saasHttp.TaskDelete(saasReq)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "submit Task delete error", "err", err) return fmt.Errorf("Submit Command error: %w", err)
return nil, err
} }
if res.Code != saasapi.ErrorCode_SUCC { if res.Code != saasapi.ErrorCode_SUCC {
err = fmt.Errorf("task delete failed. code:%v, status:%v", res.Code, res.Status) return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
fmt.Fprintln(os.Stderr, err)
return nil, err
} }
taskRes := res.GetTaskDeleteRes() taskRes := res.GetTaskDeleteRes()
fmt.Println(protojson.Format(taskRes)) fmt.Printf("task res: %v\n", protojson.Format(taskRes))
return taskRes, nil return nil
} }

View File

@@ -0,0 +1,128 @@
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 {
return fmt.Errorf("Command line parse error: %w", err)
}
if fs.NArg() > 0 || len(*sha256) == 0 || len(*destPath) == 0 {
fs.PrintDefaults()
return nil
}
cfg, err := LoadConfigFile(*cfgFile)
if err != nil {
return fmt.Errorf("LoadConfigFile error: %w", 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 {
return fmt.Errorf("download task failed: %w, task info source path is empty", 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 {
return fmt.Errorf("download block error, code %d, msg %s", blockRes.GetCode(), blockRes.GetStatus())
} 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

@@ -4,10 +4,9 @@ import (
"flag" "flag"
"fmt" "fmt"
"net/http" "net/http"
"os"
"e.coding.net/rta/public/saasapi" "git.algo.com.cn/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp" "git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
) )
@@ -17,13 +16,12 @@ type infoTaskParams struct {
} }
func RunTaskInfo(args ...string) error { func RunTaskInfo(args ...string) error {
fs := flag.NewFlagSet("create", flag.ExitOnError) fs := flag.NewFlagSet("info", flag.ExitOnError)
cfgFile := paramConfig(fs) cfgFile := paramConfig(fs)
sha256 := paramSha256(fs) sha256 := paramSha256(fs)
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err) return fmt.Errorf("Command line parse error: %w", err)
return err
} }
if fs.NArg() > 0 || len(*sha256) == 0 { if fs.NArg() > 0 || len(*sha256) == 0 {
@@ -33,25 +31,21 @@ func RunTaskInfo(args ...string) error {
cfg, err := LoadConfigFile(*cfgFile) cfg, err := LoadConfigFile(*cfgFile)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err) return fmt.Errorf("LoadConfigFile error: %w", err)
return err
} }
infoTaskParams := infoTaskParams{ infoTaskParams := infoTaskParams{
taskSha256: *sha256, taskSha256: *sha256,
saasHttp: &saashttp.SaasClient{ saasHttp: &saashttp.SaasClient{
Client: &http.Client{}, Client: &http.Client{},
ApiUrls: &cfg.ApiUrls, ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth, Auth: &cfg.Auth,
}, },
} }
taskRes, err := doTaskInfo(infoTaskParams) _, err = doTaskInfo(infoTaskParams)
if err != nil {
fmt.Printf("task res: %v\n", protojson.Format(taskRes))
}
return err return err
} }
func doTaskInfo(infoTaskParams infoTaskParams) (*saasapi.Task, error) { func doTaskInfo(infoTaskParams infoTaskParams) (*saasapi.Task, error) {
@@ -65,17 +59,15 @@ func doTaskInfo(infoTaskParams infoTaskParams) (*saasapi.Task, error) {
res, err := infoTaskParams.saasHttp.TaskInfo(saasReq) res, err := infoTaskParams.saasHttp.TaskInfo(saasReq)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "submit Task info error", "err", err) return nil, fmt.Errorf("Submit Command error: %w", err)
return nil, err
} }
if res.Code != saasapi.ErrorCode_SUCC { if res.Code != saasapi.ErrorCode_SUCC {
err = fmt.Errorf("task info failed. code:%v, status:%v", res.Code, res.Status) return nil, fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
fmt.Fprintln(os.Stderr, err)
return nil, err
} }
taskRes := res.GetTaskInfoRes() taskRes := res.GetTaskInfoRes()
fmt.Println(protojson.Format(taskRes)) fmt.Printf("task res: %v\n", protojson.Format(taskRes))
return taskRes, nil return taskRes, nil
} }

View File

@@ -4,10 +4,9 @@ import (
"flag" "flag"
"fmt" "fmt"
"net/http" "net/http"
"os"
"e.coding.net/rta/public/saasapi" "git.algo.com.cn/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp" "git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
) )
@@ -17,13 +16,12 @@ type listTaskParams struct {
} }
func RunTaskList(args ...string) error { func RunTaskList(args ...string) error {
fs := flag.NewFlagSet("create", flag.ExitOnError) fs := flag.NewFlagSet("list", flag.ExitOnError)
cfgFile := paramConfig(fs) cfgFile := paramConfig(fs)
filter := paramFilterStatus(fs) filter := paramFilterStatus(fs)
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err) return fmt.Errorf("Command line parse error: %w", err)
return err
} }
if fs.NArg() > 0 { if fs.NArg() > 0 {
@@ -33,14 +31,13 @@ func RunTaskList(args ...string) error {
cfg, err := LoadConfigFile(*cfgFile) cfg, err := LoadConfigFile(*cfgFile)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err) return fmt.Errorf("LoadConfigFile error: %w", err)
return err
} }
listTaskParams := listTaskParams{ listTaskParams := listTaskParams{
saasHttp: &saashttp.SaasClient{ saasHttp: &saashttp.SaasClient{
Client: &http.Client{}, Client: &http.Client{},
ApiUrls: &cfg.ApiUrls, ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth, Auth: &cfg.Auth,
}, },
} }
@@ -71,15 +68,12 @@ func doTaskList(listTaskParams listTaskParams) error {
} }
res, err := listTaskParams.saasHttp.TaskList(saasReq) res, err := listTaskParams.saasHttp.TaskList(saasReq)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "submit List Task error", "err", err) return fmt.Errorf("Submit Command error: %w", err)
return err
} }
if res.Code != saasapi.ErrorCode_SUCC { if res.Code != saasapi.ErrorCode_SUCC {
fmt.Fprintln(os.Stderr, "task list failed", "code", res.Code, "status", res.Status) return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
return nil
} }
taskRes := res.GetTaskListRes() taskRes := res.GetTaskListRes()

View File

@@ -7,12 +7,13 @@ import (
"fmt" "fmt"
"os" "os"
"path" "path"
"path/filepath"
"runtime" "runtime"
"sort" "sort"
"strings" "strings"
"sync" "sync"
"e.coding.net/rta/public/saasapi" "git.algo.com.cn/public/saasapi"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
) )
@@ -54,8 +55,7 @@ func RunTaskMake(args ...string) error {
ds := paramDataSpaceId(fs) ds := paramDataSpaceId(fs)
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err) return fmt.Errorf("Command line parse error: %w", err)
return err
} }
if fs.NArg() > 0 || len(*sourcePath) == 0 || len(*hashFile) == 0 || len(*ds) == 0 { if fs.NArg() > 0 || len(*sourcePath) == 0 || len(*hashFile) == 0 || len(*ds) == 0 {
@@ -63,9 +63,8 @@ func RunTaskMake(args ...string) error {
return nil return nil
} }
if strings.ToLower(*ds) == "openid" && len(*appid) == 0 { if strings.ToLower(*ds) == "wuid" && len(*appid) == 0 {
fmt.Fprintln(os.Stderr, "appid must be set when data space is openid") return fmt.Errorf("appid must be set when data space is wuid")
return nil
} }
blockSizeNum, err := ParseByteSize(*blockSize) blockSizeNum, err := ParseByteSize(*blockSize)
@@ -73,15 +72,13 @@ func RunTaskMake(args ...string) error {
fmt.Fprintln(os.Stderr, "Error parsing block size", "err", err) fmt.Fprintln(os.Stderr, "Error parsing block size", "err", err)
fmt.Fprintln(os.Stderr, "Using default 200M") fmt.Fprintln(os.Stderr, "Using default 200M")
blockSizeNum = 200 * 1024 * 1024 blockSizeNum = 200 * 1024 * 1024
} }
if blockSizeNum < blockSizeMin || blockSizeNum > blockSizeMax { if blockSizeNum < blockSizeMin || blockSizeNum > blockSizeMax {
fmt.Fprintln(os.Stderr, "block size error", "min", blockSizeMin, "max", blockSizeMax) return fmt.Errorf("block size error. min: %v, max: %v, current: %v", blockSizeMin, blockSizeMax, blockSizeNum)
return nil
} }
makeTaskParams := makeTaskParams{ makeTaskParams := &makeTaskParams{
sourcePath: *sourcePath, sourcePath: *sourcePath,
hashFile: *hashFile, hashFile: *hashFile,
task: &saasapi.Task{ task: &saasapi.Task{
@@ -89,12 +86,13 @@ func RunTaskMake(args ...string) error {
TaskDescription: *desc, TaskDescription: *desc,
Appid: *appid, Appid: *appid,
DataspaceId: *ds, 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) fsInfo, err := os.Stat(makeTaskParams.sourcePath)
if err != nil { if err != nil {
return err return err
@@ -102,9 +100,14 @@ func doMakeHash(makeTaskParams makeTaskParams) error {
if !fsInfo.IsDir() { if !fsInfo.IsDir() {
// 如果是文件,直接计算 // 如果是文件,直接计算
return doTaskMake(makeTaskParams) if firstLevel {
makeTaskParams.task.SourcePath = filepath.Dir(makeTaskParams.sourcePath)
} }
err = doTaskMake(makeTaskParams)
if err != nil {
return err
}
} else {
// 读取目录下信息 // 读取目录下信息
dirEntry, err := os.ReadDir(makeTaskParams.sourcePath) dirEntry, err := os.ReadDir(makeTaskParams.sourcePath)
if err != nil { if err != nil {
@@ -113,18 +116,23 @@ func doMakeHash(makeTaskParams makeTaskParams) error {
// 遍历目录 // 遍历目录
for _, dir := range dirEntry { for _, dir := range dirEntry {
newParam := makeTaskParams oldSourcePath := makeTaskParams.sourcePath
newParam.sourcePath = path.Join(makeTaskParams.sourcePath, dir.Name()) makeTaskParams.sourcePath = path.Join(makeTaskParams.sourcePath, dir.Name())
if err = doMakeHash(newParam); err != nil { if err = doMakeHash(makeTaskParams, false); err != nil {
return err return err
} }
makeTaskParams.sourcePath = oldSourcePath
}
} }
if firstLevel {
return saveTaskFile(makeTaskParams) return saveTaskFile(makeTaskParams)
} }
return nil
}
func doTaskMake(makeTaskParams makeTaskParams) error { func doTaskMake(makeTaskParams *makeTaskParams) error {
sourceFile, err := os.Open(makeTaskParams.sourcePath) sourceFile, err := os.Open(makeTaskParams.sourcePath)
if err != nil { if err != nil {
return err return err
@@ -200,10 +208,12 @@ func doTaskMake(makeTaskParams makeTaskParams) error {
}) })
// 输出结果 // 输出结果
relPath, _ := filepath.Rel(makeTaskParams.task.GetSourcePath(), makeTaskParams.sourcePath)
fileInfo := &saasapi.FileInfo{ fileInfo := &saasapi.FileInfo{
FileName: makeTaskParams.sourcePath, FileName: relPath,
FileSize: uint64(fi.Size()), FileSize: uint64(fi.Size()),
} }
for _, r := range allResults { for _, r := range allResults {
fileInfo.FileBlocks = append(fileInfo.FileBlocks, &saasapi.FileBlock{ fileInfo.FileBlocks = append(fileInfo.FileBlocks, &saasapi.FileBlock{
BlockSha256: r.hash, BlockSha256: r.hash,
@@ -212,6 +222,8 @@ func doTaskMake(makeTaskParams makeTaskParams) error {
} }
makeTaskParams.task.TaskFileInfos = append(makeTaskParams.task.TaskFileInfos, fileInfo) makeTaskParams.task.TaskFileInfos = append(makeTaskParams.task.TaskFileInfos, fileInfo)
makeTaskParams.task.TaskSize += uint64(fi.Size())
fmt.Println("") fmt.Println("")
return nil return nil
} }
@@ -227,7 +239,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) taskFile, err := os.Create(makeTaskParams.hashFile)
if err != nil { if err != nil {
return err return err

View File

@@ -4,10 +4,9 @@ import (
"flag" "flag"
"fmt" "fmt"
"net/http" "net/http"
"os"
"e.coding.net/rta/public/saasapi" "git.algo.com.cn/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp" "git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
) )
@@ -17,13 +16,12 @@ type runTaskParams struct {
} }
func RunTaskRun(args ...string) error { func RunTaskRun(args ...string) error {
fs := flag.NewFlagSet("create", flag.ExitOnError) fs := flag.NewFlagSet("run", flag.ExitOnError)
cfgFile := paramConfig(fs) cfgFile := paramConfig(fs)
sha256 := paramSha256(fs) sha256 := paramSha256(fs)
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err) return fmt.Errorf("Command line parse error: %w", err)
return err
} }
if fs.NArg() > 0 || len(*sha256) == 0 { if fs.NArg() > 0 || len(*sha256) == 0 {
@@ -33,15 +31,14 @@ func RunTaskRun(args ...string) error {
cfg, err := LoadConfigFile(*cfgFile) cfg, err := LoadConfigFile(*cfgFile)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err) return fmt.Errorf("LoadConfigFile error: %w", err)
return err
} }
runTaskParams := runTaskParams{ runTaskParams := runTaskParams{
taskSha256: *sha256, taskSha256: *sha256,
saasHttp: &saashttp.SaasClient{ saasHttp: &saashttp.SaasClient{
Client: &http.Client{}, Client: &http.Client{},
ApiUrls: &cfg.ApiUrls, ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth, Auth: &cfg.Auth,
}, },
} }
@@ -61,14 +58,11 @@ func doTaskRun(runTaskParams runTaskParams) error {
res, err := runTaskParams.saasHttp.TaskRun(saasReq) res, err := runTaskParams.saasHttp.TaskRun(saasReq)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "submit Task run error", "err", err) return fmt.Errorf("Submit Command error: %w", err)
return err
} }
if res.Code != saasapi.ErrorCode_SUCC { if res.Code != saasapi.ErrorCode_SUCC {
err = fmt.Errorf("task run failed. code:%v, status:%v", res.Code, res.Status) return fmt.Errorf("Command failed. code:%v, status:%v", res.Code, res.Status)
fmt.Fprintln(os.Stderr, err)
return err
} }
fmt.Println("task run success", protojson.Format(res)) fmt.Println("task run success", protojson.Format(res))

View File

@@ -5,9 +5,10 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"os" "os"
"path/filepath"
"e.coding.net/rta/public/saasapi" "git.algo.com.cn/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp" "git.algo.com.cn/public/saasapi/pkg/saashttp"
) )
type uploadTaskParams struct { type uploadTaskParams struct {
@@ -21,8 +22,7 @@ func RunTaskUpload(args ...string) error {
sha256 := paramSha256(fs) sha256 := paramSha256(fs)
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err) return fmt.Errorf("Command line parse error: %w", err)
return err
} }
if fs.NArg() > 0 || len(*sha256) == 0 { if fs.NArg() > 0 || len(*sha256) == 0 {
@@ -32,22 +32,21 @@ func RunTaskUpload(args ...string) error {
cfg, err := LoadConfigFile(*cfgFile) cfg, err := LoadConfigFile(*cfgFile)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "LoadConfigFile error", "err", err) return fmt.Errorf("LoadConfigFile error: %w", err)
return err
} }
uploadTaskParams := uploadTaskParams{ uploadTaskParams := uploadTaskParams{
taskSha256: *sha256, taskSha256: *sha256,
saasHttp: &saashttp.SaasClient{ saasHttp: &saashttp.SaasClient{
Client: &http.Client{}, Client: &http.Client{},
ApiUrls: &cfg.ApiUrls, ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth, Auth: &cfg.Auth,
}, },
} }
return doTaskUpload(uploadTaskParams) return doTaskUpload(uploadTaskParams)
} }
func doTaskUpload(uploadTaskParams uploadTaskParams) error { func doTaskUpload(uploadTaskParams uploadTaskParams) error {
infoTaskParams := infoTaskParams{ infoTaskParams := infoTaskParams{
taskSha256: uploadTaskParams.taskSha256, taskSha256: uploadTaskParams.taskSha256,
@@ -58,10 +57,10 @@ func doTaskUpload(uploadTaskParams uploadTaskParams) error {
return err return err
} }
sourcePath := taskInfo.GetSourcePath()
totalFiles := len(taskInfo.GetTaskFileInfos()) totalFiles := len(taskInfo.GetTaskFileInfos())
fi := 0 fi := 0
for _, finfo := range taskInfo.GetTaskFileInfos() { for _, finfo := range taskInfo.GetTaskFileInfos() {
fi++ fi++
var f *os.File var f *os.File
offset := int64(0) offset := int64(0)
@@ -71,7 +70,11 @@ func doTaskUpload(uploadTaskParams uploadTaskParams) error {
bi++ bi++
if !binfo.GetUploaded() { if !binfo.GetUploaded() {
if f == nil { 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 { if err != nil {
return err return err
} }

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" "path"
"strings" "strings"
"e.coding.net/rta/public/saasapi" "git.algo.com.cn/public/saasapi"
"e.coding.net/rta/public/saasapi/pkg/saashttp" "git.algo.com.cn/public/saasapi/pkg/saashttp"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
) )
@@ -34,8 +34,7 @@ func RunWrite(args ...string) error {
clear := paramClear(fs) clear := paramClear(fs)
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
fmt.Fprintln(os.Stderr, "command line parse error", "err", err) return fmt.Errorf("Command line parse error: %w", err)
return err
} }
if fs.NArg() > 0 || len(*sourcePath) == 0 || len(*ds) == 0 { if fs.NArg() > 0 || len(*sourcePath) == 0 || len(*ds) == 0 {
@@ -43,15 +42,14 @@ func RunWrite(args ...string) error {
return nil return nil
} }
if strings.ToLower(*ds) == "openid" && len(*appid) == 0 { if strings.ToLower(*ds) == "wuid" && len(*appid) == 0 {
fmt.Fprintln(os.Stderr, "appid must be set when data space is openid") fmt.Fprintln(os.Stderr, "appid must be set when data space is wuid")
return nil return nil
} }
cfg, err := LoadConfigFile(*cfgFile) cfg, err := LoadConfigFile(*cfgFile)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "load config file error", "err", err) return fmt.Errorf("LoadConfigFile error: %w", err)
return err
} }
writeParams := writeParams{ writeParams := writeParams{
@@ -63,7 +61,7 @@ func RunWrite(args ...string) error {
clear: *clear, clear: *clear,
saasHttp: &saashttp.SaasClient{ saasHttp: &saashttp.SaasClient{
Client: &http.Client{}, Client: &http.Client{},
ApiUrls: &cfg.ApiUrls, ApiUrls: saashttp.InitAPIUrl(&cfg.ApiUrls),
Auth: &cfg.Auth, Auth: &cfg.Auth,
}, },
} }
@@ -74,8 +72,7 @@ func RunWrite(args ...string) error {
func doWrite(writeParams writeParams) error { func doWrite(writeParams writeParams) error {
fsInfo, err := os.Stat(writeParams.sourcePath) fsInfo, err := os.Stat(writeParams.sourcePath)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "file stat error", "err", err) return fmt.Errorf("file stat error: %w", err)
return err
} }
if !fsInfo.IsDir() { if !fsInfo.IsDir() {
@@ -86,8 +83,7 @@ func doWrite(writeParams writeParams) error {
// 读取目录下信息 // 读取目录下信息
dirEntry, err := os.ReadDir(writeParams.sourcePath) dirEntry, err := os.ReadDir(writeParams.sourcePath)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "read dir error", "err", err) return fmt.Errorf("read dir error: %w", err)
return err
} }
// 遍历目录 // 遍历目录
@@ -107,8 +103,7 @@ func doLoadFileToWrite(writeParams writeParams) error {
// 读取文件并按行遍历,以\t分割为两列第一列为userid第二列解析为string数组 // 读取文件并按行遍历,以\t分割为两列第一列为userid第二列解析为string数组
file, err := os.Open(writeParams.sourcePath) file, err := os.Open(writeParams.sourcePath)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "open file error", "file", writeParams.sourcePath, "err", err) return fmt.Errorf("open file error: %w. file: %v", err, writeParams.sourcePath)
return err
} }
defer file.Close() defer file.Close()
@@ -127,8 +122,7 @@ func doLoadFileToWrite(writeParams writeParams) error {
} }
saasWriteItem := &saasapi.WriteItem{} saasWriteItem := &saasapi.WriteItem{}
if err = protojson.Unmarshal([]byte(line), saasWriteItem); err != nil { if err = protojson.Unmarshal([]byte(line), saasWriteItem); err != nil {
fmt.Fprintln(os.Stderr, "protojson unmashal error", "file", writeParams.sourcePath, "line", total, "err", err) return fmt.Errorf("protojson unmashal error: %w. file: %v line: %v", err, writeParams.sourcePath, total)
return err
} }
saasWriteItems = append(saasWriteItems, saasWriteItem) saasWriteItems = append(saasWriteItems, saasWriteItem)
@@ -171,15 +165,12 @@ func submitWrite(writeParams writeParams, saasWriteCmds []*saasapi.WriteItem) (e
write.WriteItems = saasWriteCmds write.WriteItems = saasWriteCmds
res, err := writeParams.saasHttp.Write(saasReq) res, err := writeParams.saasHttp.Write(saasReq)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "submit write error", "err", err) return 0, fmt.Errorf("Submit Command error: %w", err)
return
} }
if res.GetCode() != saasapi.ErrorCode_SUCC { if res.GetCode() != saasapi.ErrorCode_SUCC {
err = fmt.Errorf("write failed. code:%v, status:%v", res.GetCode(), res.GetStatus()) err = fmt.Errorf("write failed. code:%v, status:%v", res.GetCode(), res.GetStatus())
fmt.Fprintln(os.Stderr, protojson.Format(res))
return return
} }

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}}}

9
docker/build_saastool.sh Executable file
View File

@@ -0,0 +1,9 @@
#/bin/sh -v
set -e
docker buildx build --platform linux/amd64 \
-t rta-docker.pkg.coding.net/public/docker/saastool:2026011914 \
-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 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,257 @@
package saashttp package saashttp
const (
baseUrl = "https://api.rta.qq.com"
infoPath = "/saas/info"
writePath = "/saas/write"
readPath = "/saas/read"
columnWritePath = "/saas/column_write"
resetDSPath = "/saas/resetds"
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"
scriptDebugPath = "/saas/script/debug"
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 { type ApiUrls struct {
BaseUrl string BaseUrl string
InfoPath string
WritePath string WritePath string
ReadPath string ReadPath string
ColumnWritePath string ColumnWritePath string
ResetDSPath string
TaskCreatePath string TaskCreatePath string
TaskListPath string TaskListPath string
TaskInfoPath string TaskInfoPath string
TaskDeletePath string TaskDeletePath string
TaskRunPath string TaskRunPath string
TaskUploadPath string TaskUploadPath string
TaskDownloadPath string
TargetListPath string
TargetCreatePath string
TargetDeletePath string
BindSetPath string
BindDeletePath string
ScriptDebugPath 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
} }
type Auth struct { func InitAPIUrl(c *ApiUrls) *ApiUrls {
Account string r := &ApiUrls{}
Token string 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.ResetDSPath != "" {
r.ResetDSPath = c.ResetDSPath
} else {
r.ResetDSPath = resetDSPath
}
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.ScriptDebugPath != "" {
r.ScriptDebugPath = c.ScriptDebugPath
} else {
r.ScriptDebugPath = scriptDebugPath
}
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" "net/url"
"os" "os"
"strconv" "strconv"
"strings"
"time" "time"
"e.coding.net/rta/public/saasapi" "git.algo.com.cn/public/saasapi"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
@@ -32,6 +33,11 @@ type SaasClient struct {
ResponseEncoder ResponseEncoder 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) { func (c *SaasClient) Write(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.WritePath) postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.WritePath)
return c.post(postUrl, saasReq) return c.post(postUrl, saasReq)
@@ -47,6 +53,11 @@ func (c *SaasClient) ColumnWrite(saasReq *saasapi.SaasReq) (saasRes *saasapi.Saa
return c.post(postUrl, saasReq) return c.post(postUrl, saasReq)
} }
func (c *SaasClient) ResetDS(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ResetDSPath)
return c.post(postUrl, saasReq)
}
func (c *SaasClient) TaskCreate(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) { func (c *SaasClient) TaskCreate(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.TaskCreatePath) postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.TaskCreatePath)
return c.post(postUrl, saasReq) return c.post(postUrl, saasReq)
@@ -77,6 +88,81 @@ func (c *SaasClient) TaskUpload(sha256 string, file *os.File, offset int64, size
return c.upload(postUrl, file, offset, 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) ScriptDebug(saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postUrl := c.makeUrl(c.ApiUrls.BaseUrl, c.ApiUrls.ScriptDebugPath)
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 { func (c *SaasClient) makeUrl(baseUrl, path string, params ...string) string {
url, err := url.Parse(baseUrl) url, err := url.Parse(baseUrl)
if err != nil { if err != nil {
@@ -105,14 +191,12 @@ func (c *SaasClient) makeUrl(baseUrl, path string, params ...string) string {
func (c *SaasClient) post(url string, saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) { func (c *SaasClient) post(url string, saasReq *saasapi.SaasReq) (saasRes *saasapi.SaasRes, err error) {
postBuf, err := proto.Marshal(saasReq) postBuf, err := proto.Marshal(saasReq)
if err != nil { if err != nil {
fmt.Println("marshal saas req error", err) return nil, fmt.Errorf("Marshal saas req error. %w", err)
return nil, err
} }
req, err := http.NewRequest("POST", url, bytes.NewBuffer(postBuf)) req, err := http.NewRequest("POST", url, bytes.NewBuffer(postBuf))
if err != nil { if err != nil {
fmt.Println("http new request error", err) return nil, fmt.Errorf("Http new request error. %w", err)
return nil, err
} }
timeStamp := strconv.FormatInt(time.Now().Unix(), 10) timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
@@ -125,30 +209,30 @@ func (c *SaasClient) post(url string, saasReq *saasapi.SaasReq) (saasRes *saasap
req.Header.Add("Content-Type", "application/x-protobuf") req.Header.Add("Content-Type", "application/x-protobuf")
res, err := c.Client.Do(req) res, err := c.Client.Do(req)
if err != nil { if err != nil {
fmt.Println("http send error", err) return nil, fmt.Errorf("Http do request error. %w", err)
return nil, err
} }
defer res.Body.Close() defer res.Body.Close()
if res.StatusCode != 200 {
return nil, fmt.Errorf("NOT 200. %v", res.StatusCode)
}
resBody, err := io.ReadAll(res.Body) resBody, err := io.ReadAll(res.Body)
if err != nil { if err != nil {
fmt.Println("http read body error", err) return nil, fmt.Errorf("Http read body error. %w", err)
return nil, err
} }
saasRes = &saasapi.SaasRes{} saasRes = &saasapi.SaasRes{}
if c.ResponseEncoder == RESPONSE_ENCODER_PROTOBUF { if c.ResponseEncoder == RESPONSE_ENCODER_PROTOBUF {
err = proto.Unmarshal(resBody, saasRes) err = proto.Unmarshal(resBody, saasRes)
if err != nil { if err != nil {
fmt.Println("unmarshal response body to protobuf error", err) return nil, fmt.Errorf("unmarshal response body to protobuf error. %w", err)
return nil, err
} }
} else { } else {
err = json.Unmarshal(resBody, saasRes) err = json.Unmarshal(resBody, saasRes)
if err != nil { if err != nil {
fmt.Println("unmarshal response body to json error", err) return nil, fmt.Errorf("unmarshal response body to json error. %w", err)
return nil, err
} }
} }
@@ -157,39 +241,36 @@ func (c *SaasClient) post(url string, saasReq *saasapi.SaasReq) (saasRes *saasap
func (c *SaasClient) upload(url string, file *os.File, offset int64, size int) (saasRes *saasapi.SaasRes, err error) { func (c *SaasClient) upload(url string, file *os.File, offset int64, size int) (saasRes *saasapi.SaasRes, err error) {
if file == nil { if file == nil {
return nil, fmt.Errorf("file is nil") return nil, fmt.Errorf("file is nil.")
} }
if size <= 0 { if size <= 0 {
return nil, fmt.Errorf("size is invalid") return nil, fmt.Errorf("size is invalid.")
} }
buf := make([]byte, size) buf := make([]byte, size)
n, err := file.ReadAt(buf, offset) n, err := file.ReadAt(buf, offset)
if err != nil { if err != nil {
fmt.Println("read file error", err) return nil, fmt.Errorf("Read file error. %w", err)
return nil, err
} }
if n != size { if n != size {
return nil, fmt.Errorf("read file error") return nil, fmt.Errorf("Read file size not match. %v", n)
} }
var gzBuf bytes.Buffer var gzBuf bytes.Buffer
gz := gzip.NewWriter(&gzBuf) gz := gzip.NewWriter(&gzBuf)
if _, err := gz.Write(buf); err != nil { if _, err := gz.Write(buf); err != nil {
fmt.Println("gzip write error", err) return nil, fmt.Errorf("GZip write error. %w", err)
return nil, err
} }
if err = gz.Close(); err != nil { if err = gz.Close(); err != nil {
return nil, err return nil, fmt.Errorf("GZip close error. %w", err)
} }
req, err := http.NewRequest("POST", url, bytes.NewBuffer(gzBuf.Bytes())) req, err := http.NewRequest("POST", url, bytes.NewBuffer(gzBuf.Bytes()))
if err != nil { if err != nil {
fmt.Println("http new request error", err) return nil, fmt.Errorf("Http new request error. %w", err)
return nil, err
} }
timeStamp := strconv.FormatInt(time.Now().Unix(), 10) timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
@@ -203,32 +284,130 @@ func (c *SaasClient) upload(url string, file *os.File, offset int64, size int) (
req.Header.Add("Content-Encoding", "gzip") req.Header.Add("Content-Encoding", "gzip")
res, err := c.Client.Do(req) res, err := c.Client.Do(req)
if err != nil { if err != nil {
fmt.Println("http send error", err) return nil, fmt.Errorf("Http do request error. %w", err)
return nil, err
} }
defer res.Body.Close() defer res.Body.Close()
if res.StatusCode != 200 {
return nil, fmt.Errorf("NOT 200. %v", res.StatusCode)
}
resBody, err := io.ReadAll(res.Body) resBody, err := io.ReadAll(res.Body)
if err != nil { if err != nil {
fmt.Println("http read body error", err) return nil, fmt.Errorf("http read body error. %w", err)
return nil, err
} }
saasRes = &saasapi.SaasRes{} saasRes = &saasapi.SaasRes{}
if c.ResponseEncoder == RESPONSE_ENCODER_PROTOBUF { if c.ResponseEncoder == RESPONSE_ENCODER_PROTOBUF {
err = proto.Unmarshal(resBody, saasRes) err = proto.Unmarshal(resBody, saasRes)
if err != nil { if err != nil {
fmt.Println("unmarshal response body to protobuf error", err) return nil, fmt.Errorf("unmarshal response body to protobuf error. %w", err)
return nil, err
} }
} else { } else {
err = json.Unmarshal(resBody, saasRes) err = json.Unmarshal(resBody, saasRes)
if err != nil { if err != nil {
fmt.Println("unmarshal response body to json error", err) return nil, fmt.Errorf("unmarshal response body to json error. %w", err)
return nil, err
} }
} }
return saasRes, nil 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 {
return nil, fmt.Errorf("Http new request error. %w", 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 {
return nil, fmt.Errorf("Http do request error. %w", err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
return nil, fmt.Errorf("http state error. %w", err)
}
bodyReader := res.Body
if strings.Contains(res.Header.Get("Content-Encoding"), "gzip") {
gz, err := gzip.NewReader(res.Body)
if err != nil {
return nil, fmt.Errorf("GZip newreader error. %w", err)
}
defer gz.Close()
bodyReader = gz
}
resBody, err := io.ReadAll(bodyReader)
if err != nil {
return nil, fmt.Errorf("Http read body error. %w", err)
}
saasRes = &saasapi.SaasRes{}
if strings.Contains(res.Header.Get("Content-Type"), "application/octet-stream") {
if len(resBody) == size {
file.WriteAt(resBody, offset)
} else {
return nil, fmt.Errorf("body size error. body:%v, want:%v", len(resBody), size)
}
} else {
if c.ResponseEncoder == RESPONSE_ENCODER_PROTOBUF {
err = proto.Unmarshal(resBody, saasRes)
if err != nil {
return nil, fmt.Errorf("unmarshal response body to protobuf error. %w", err)
}
} else {
err = json.Unmarshal(resBody, saasRes)
if err != nil {
return nil, fmt.Errorf("unmarshal response body to json error. %w", 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)
}