dts-dance 0.2.2__py3-none-any.whl → 0.2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dts_dance-0.2.2.dist-info → dts_dance-0.2.4.dist-info}/METADATA +3 -2
- dts_dance-0.2.4.dist-info/RECORD +14 -0
- dtsdance/bytecloud.py +2 -2
- dtsdance/dflow.py +4 -4
- dtsdance/feishu_base.py +193 -4
- dtsdance/feishu_table.py +71 -9
- dtsdance/spacex_bytedts.py +48 -0
- dts_dance-0.2.2.dist-info/RECORD +0 -14
- {dts_dance-0.2.2.dist-info → dts_dance-0.2.4.dist-info}/WHEEL +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dts-dance
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: dts dance lib
|
|
5
5
|
Keywords: observation,tools
|
|
6
6
|
Requires-Python: >=3.12
|
|
7
|
-
Requires-Dist: boto3<2.0.0,>=1.42.
|
|
7
|
+
Requires-Dist: boto3<2.0.0,>=1.42.30
|
|
8
8
|
Requires-Dist: loguru<0.8.0,>=0.7.3
|
|
9
9
|
Requires-Dist: pyyaml<7.0.0,>=6.0.3
|
|
10
|
+
Requires-Dist: requests-toolbelt==1.0.0
|
|
10
11
|
Requires-Dist: requests<3.0.0,>=2.32.5
|
|
11
12
|
Description-Content-Type: text/markdown
|
|
12
13
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
dtsdance/__init__.py,sha256=Yl_jEZ5weYfcrklnDvwB4wSgCOvMBLRRgWx0gHs3qfM,49
|
|
2
|
+
dtsdance/bytecloud.py,sha256=s1suo-YexMH6gUHYwC6P5k6AeyOm7Q_acYh_gHCDVjI,5654
|
|
3
|
+
dtsdance/dflow.py,sha256=ggwNB2x-LgnpI9nzNTTnYnGfYyGH5rYcHHBhC4pOlfg,7059
|
|
4
|
+
dtsdance/dsyncer.py,sha256=3Oj1Ko5FuB_sUm9Hj-hBy95wee3b6TH2FXKoPFGsakM,11193
|
|
5
|
+
dtsdance/feishu_base.py,sha256=Dsl8CZZ3wyZf3TEiiUAs3_WpX1pinCuWFwqpm29ROVc,10414
|
|
6
|
+
dtsdance/feishu_table.py,sha256=JleCjQJ-rcbC15v2UAc5BK-YioB2SMGsdGztQ9BaT4k,10779
|
|
7
|
+
dtsdance/metrics_fe.py,sha256=hzIl5BJmuCrkqJOHELVzXm3YAqrPttbyVkKBglS4mgQ,18978
|
|
8
|
+
dtsdance/s3.py,sha256=Bh-cwLksfO5PewNtIzE_Md3rRLDLI1DUVoOD7Pou5T8,1294
|
|
9
|
+
dtsdance/spacex_bytedts.py,sha256=oVnHXTj-cuq2vcsUJq33_aaq0TQp7A52kldvspKueI4,4799
|
|
10
|
+
dtsdance/tcc_inner.py,sha256=6Tuq_r2nNCK_HC4hqEGh7UVAa8kDtuIcU95WBu4zuFQ,1623
|
|
11
|
+
dtsdance/tcc_open.py,sha256=Qb_ue3xH0CSsoReItdFKuvW7JsDTfFkDNIB_4zjzSQI,6893
|
|
12
|
+
dts_dance-0.2.4.dist-info/METADATA,sha256=LY_7WWh06QNmhr_1vyuMTtKDrx88N0P1BjGEURYAl6U,833
|
|
13
|
+
dts_dance-0.2.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
14
|
+
dts_dance-0.2.4.dist-info/RECORD,,
|
dtsdance/bytecloud.py
CHANGED
|
@@ -20,9 +20,9 @@ class ByteCloudClient:
|
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
# 每小时刷新一次,单位为秒
|
|
23
|
-
_REFRESH_INTERVAL =
|
|
23
|
+
_REFRESH_INTERVAL = 2 * 60 * 60
|
|
24
24
|
|
|
25
|
-
def __init__(self,
|
|
25
|
+
def __init__(self, sites: dict[str, SiteConfig] | None = None, enable_jwt_cache: bool = False) -> None:
|
|
26
26
|
"""
|
|
27
27
|
初始化 ByteCloud Client
|
|
28
28
|
从配置文件加载所有环境的信息,并为每个环境初始化 JWT 令牌
|
dtsdance/dflow.py
CHANGED
|
@@ -150,7 +150,7 @@ class DFlowClient:
|
|
|
150
150
|
"""
|
|
151
151
|
# 根据环境生成对应的 scope 参数
|
|
152
152
|
site_info = self.bytecloud_client.get_site_config(site)
|
|
153
|
-
return f"{site_info.endpoint}/bytedts/datasync/detail/{task_id}
|
|
153
|
+
return f"{site_info.endpoint}/bytedts/datasync/detail/{task_id}"
|
|
154
154
|
|
|
155
155
|
def init_resources(self, site: str, ctrl_env: str) -> bool:
|
|
156
156
|
"""
|
|
@@ -179,7 +179,7 @@ class DFlowClient:
|
|
|
179
179
|
|
|
180
180
|
def list_resources(self, site: str, ctrl_env: str) -> list[str]:
|
|
181
181
|
"""
|
|
182
|
-
列举 CTRL
|
|
182
|
+
列举 CTRL 环境资源列表,连同 agent 列表
|
|
183
183
|
|
|
184
184
|
Args:
|
|
185
185
|
site: 站点名称
|
|
@@ -198,8 +198,8 @@ class DFlowClient:
|
|
|
198
198
|
response_data = self._make_request("POST", url, self.bytecloud_client.build_request_headers(site), json_data)
|
|
199
199
|
|
|
200
200
|
try:
|
|
201
|
-
data =
|
|
202
|
-
items =
|
|
201
|
+
data = response_data.get("data", {})
|
|
202
|
+
items = data.get("items", [])
|
|
203
203
|
return [item["name"] for item in items]
|
|
204
204
|
except (KeyError, AttributeError, Exception) as e:
|
|
205
205
|
raise Exception(f"无法从响应中提取 CTRL 环境资源列表数据: {str(e)}")
|
dtsdance/feishu_base.py
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
from datetime import datetime, timedelta
|
|
2
2
|
import threading
|
|
3
|
-
|
|
3
|
+
import json
|
|
4
4
|
from loguru import logger
|
|
5
|
+
from typing import Any
|
|
6
|
+
from requests_toolbelt import MultipartEncoder
|
|
7
|
+
|
|
5
8
|
import requests
|
|
6
9
|
|
|
7
10
|
URL_FEISHU_OPEN_API: str = "https://fsopen.bytedance.net/open-apis"
|
|
@@ -14,8 +17,8 @@ class FeishuBase:
|
|
|
14
17
|
"""
|
|
15
18
|
初始化飞书基础类
|
|
16
19
|
"""
|
|
17
|
-
self.tenant_access_token:
|
|
18
|
-
self.token_expire_time:
|
|
20
|
+
self.tenant_access_token: str | None = None
|
|
21
|
+
self.token_expire_time: datetime | None = None
|
|
19
22
|
self._token_lock = threading.Lock()
|
|
20
23
|
|
|
21
24
|
self.bot_app_id = bot_app_id
|
|
@@ -99,9 +102,195 @@ class FeishuBase:
|
|
|
99
102
|
|
|
100
103
|
try:
|
|
101
104
|
response = requests.request(method, url, **kwargs)
|
|
102
|
-
|
|
105
|
+
logger.debug(f"response_json: {response.json()}")
|
|
103
106
|
response.raise_for_status()
|
|
104
107
|
return response
|
|
105
108
|
except requests.RequestException as e:
|
|
106
109
|
logger.warning(f"API请求失败: {method} {url}, error: {e}")
|
|
107
110
|
raise
|
|
111
|
+
|
|
112
|
+
def upload_image(self, image_path: str) -> str | None:
|
|
113
|
+
"""
|
|
114
|
+
上传图片到飞书
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
image_path: 图片文件路径
|
|
118
|
+
image_type: 图片类型,默认为'message'
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
image_key
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
if not image_path:
|
|
125
|
+
raise ValueError("必须提供image_path")
|
|
126
|
+
|
|
127
|
+
file_obj = None
|
|
128
|
+
try:
|
|
129
|
+
# 准备文件
|
|
130
|
+
file_obj = open(image_path, "rb")
|
|
131
|
+
file_name = image_path.split("/")[-1]
|
|
132
|
+
|
|
133
|
+
# 构建表单数据
|
|
134
|
+
form = {"image_type": "message", "image": (file_name, file_obj, "image/png")}
|
|
135
|
+
multi_form = MultipartEncoder(form)
|
|
136
|
+
headers = {"Content-Type": multi_form.content_type}
|
|
137
|
+
response = self.make_request("POST", "/im/v1/images", headers=headers, data=multi_form)
|
|
138
|
+
result = response.json()
|
|
139
|
+
if result.get("code") != 0:
|
|
140
|
+
raise Exception(f"上传图片失败: {result.get('msg')}")
|
|
141
|
+
|
|
142
|
+
logger.info(f"图片上传成功,image_key: {result.get('data', {}).get('image_key')}")
|
|
143
|
+
logger.debug(f"上传响应logid: {response.headers.get('X-Tt-Logid')}")
|
|
144
|
+
|
|
145
|
+
return result.get("data", {}).get("image_key")
|
|
146
|
+
|
|
147
|
+
except Exception as e:
|
|
148
|
+
logger.warning(f"上传图片失败: {e}")
|
|
149
|
+
return None
|
|
150
|
+
finally:
|
|
151
|
+
# 如果是通过路径打开的文件,需要关闭
|
|
152
|
+
if image_path and file_obj and hasattr(file_obj, "close"):
|
|
153
|
+
file_obj.close()
|
|
154
|
+
|
|
155
|
+
def send_text_message(self, receive_id: str, text: str, receive_id_type: str) -> dict[str, Any]:
|
|
156
|
+
"""
|
|
157
|
+
发送文本消息
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
receive_id: 接收者ID(群聊ID、用户ID等)
|
|
161
|
+
text: 消息文本内容
|
|
162
|
+
receive_id_type: 接收者ID类型,可选值:open_id, user_id, union_id, email, chat_id
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
发送结果
|
|
166
|
+
"""
|
|
167
|
+
content = json.dumps({"text": text}, ensure_ascii=False)
|
|
168
|
+
return self.send_message(receive_id, "text", content, receive_id_type)
|
|
169
|
+
|
|
170
|
+
def send_image_message(self, receive_id: str, image_key: str, receive_id_type: str) -> dict[str, Any]:
|
|
171
|
+
"""
|
|
172
|
+
发送图片消息
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
receive_id: 接收者ID
|
|
176
|
+
image_key: 图片key(通过upload_image获取)
|
|
177
|
+
receive_id_type: 接收者ID类型
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
发送结果
|
|
181
|
+
"""
|
|
182
|
+
content = json.dumps({"image_key": image_key}, ensure_ascii=False)
|
|
183
|
+
return self.send_message(receive_id, "image", content, receive_id_type)
|
|
184
|
+
|
|
185
|
+
def send_card_message(self, receive_id: str, header: dict, elements: list, receive_id_type: str) -> dict[str, Any]:
|
|
186
|
+
"""
|
|
187
|
+
发送卡片消息
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
receive_id: 接收者ID
|
|
191
|
+
header: 卡片消息的头部内容(符合飞书卡片规范的JSON)
|
|
192
|
+
elements: 卡片消息的主体元素列表
|
|
193
|
+
receive_id_type: 接收者ID类型
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
发送结果
|
|
197
|
+
"""
|
|
198
|
+
card_content = {"schema": "2.0", "config": {"update_multi": True}, "body": {"direction": "vertical", "elements": elements}, "header": header}
|
|
199
|
+
content = json.dumps(card_content, ensure_ascii=False)
|
|
200
|
+
return self.send_message(receive_id, "interactive", content, receive_id_type)
|
|
201
|
+
|
|
202
|
+
def send_message(self, receive_id: str, msg_type: str, content: str, receive_id_type: str = "chat_id") -> dict[str, Any]:
|
|
203
|
+
"""
|
|
204
|
+
发送消息的通用方法
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
receive_id: 接收者ID
|
|
208
|
+
msg_type: 消息类型(text, image, card等)
|
|
209
|
+
content: 消息内容
|
|
210
|
+
receive_id_type: 接收者ID类型
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
发送结果
|
|
214
|
+
|
|
215
|
+
Raises:
|
|
216
|
+
Exception: 发送失败
|
|
217
|
+
"""
|
|
218
|
+
payload = {"receive_id": receive_id, "msg_type": msg_type, "content": content}
|
|
219
|
+
params = {"receive_id_type": receive_id_type}
|
|
220
|
+
|
|
221
|
+
try:
|
|
222
|
+
response = self.make_request("POST", "/im/v1/messages", json=payload, params=params)
|
|
223
|
+
result = response.json()
|
|
224
|
+
if result.get("code") != 0:
|
|
225
|
+
raise Exception(f"请求失败: {result.get('msg')}")
|
|
226
|
+
|
|
227
|
+
logger.info(f"消息发送成功,message_id: {result.get('data', {}).get('message_id')}")
|
|
228
|
+
logger.debug(f"发送响应logid: {response.headers.get('X-Tt-Logid')}")
|
|
229
|
+
|
|
230
|
+
return result.get("data", {})
|
|
231
|
+
|
|
232
|
+
except Exception as e:
|
|
233
|
+
logger.warning(f"发送消息失败: {e}")
|
|
234
|
+
raise
|
|
235
|
+
|
|
236
|
+
def reply_message(self, message_id: str, msg_type: str, content: str) -> dict[str, Any]:
|
|
237
|
+
"""
|
|
238
|
+
回复某条消息
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
message_id: 消息ID
|
|
242
|
+
msg_type: 消息类型(text, image, card等)
|
|
243
|
+
content: 消息内容
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
回复结果
|
|
247
|
+
|
|
248
|
+
Raises:
|
|
249
|
+
Exception: 回复失败
|
|
250
|
+
"""
|
|
251
|
+
payload = {"reply_in_thread": False, "msg_type": msg_type, "content": content}
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
response = self.make_request("POST", f"/im/v1/messages/{message_id}/reply", json=payload)
|
|
255
|
+
result = response.json()
|
|
256
|
+
if result.get("code") != 0:
|
|
257
|
+
raise Exception(f"请求失败: {result.get('msg')}")
|
|
258
|
+
|
|
259
|
+
logger.info(f"消息回复成功,message_id: {result.get('data', {}).get('message_id')}")
|
|
260
|
+
logger.debug(f"发送响应logid: {response.headers.get('X-Tt-Logid')}")
|
|
261
|
+
|
|
262
|
+
return result.get("data", {})
|
|
263
|
+
|
|
264
|
+
except Exception as e:
|
|
265
|
+
logger.warning(f"回复消息失败: {e}")
|
|
266
|
+
raise
|
|
267
|
+
|
|
268
|
+
def batch_get_user_ids(self, emails: list[str]) -> list[str]:
|
|
269
|
+
"""
|
|
270
|
+
批量获取用户ID
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
emails: 用户邮箱列表
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
批量获取结果(用户ID列表)
|
|
277
|
+
|
|
278
|
+
Raises:
|
|
279
|
+
Exception: 获取失败
|
|
280
|
+
"""
|
|
281
|
+
payload = {"emails": emails, "include_resigned": False}
|
|
282
|
+
|
|
283
|
+
try:
|
|
284
|
+
response = self.make_request("POST", f"/contact/v3/users/batch_get_id?user_id_type=user_id", json=payload)
|
|
285
|
+
result = response.json()
|
|
286
|
+
if result.get("code") != 0:
|
|
287
|
+
raise Exception(f"请求失败: {result.get('msg')}")
|
|
288
|
+
|
|
289
|
+
user_ids = [user.get("user_id") for user in result.get("data", {}).get("user_list", [])]
|
|
290
|
+
|
|
291
|
+
logger.debug(f"发送响应logid: {response.headers.get('X-Tt-Logid')}")
|
|
292
|
+
|
|
293
|
+
return user_ids
|
|
294
|
+
except Exception as e:
|
|
295
|
+
logger.warning(f"批量获取用户ID失败: {e}")
|
|
296
|
+
raise
|
dtsdance/feishu_table.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
import threading
|
|
3
|
-
from typing import Callable,
|
|
3
|
+
from typing import Callable, Any
|
|
4
4
|
from loguru import logger
|
|
5
5
|
import requests
|
|
6
6
|
|
|
@@ -16,15 +16,15 @@ class FeishuTable:
|
|
|
16
16
|
"""
|
|
17
17
|
初始化飞书表格
|
|
18
18
|
"""
|
|
19
|
-
self.tenant_access_token:
|
|
20
|
-
self.token_expire_time:
|
|
19
|
+
self.tenant_access_token: str | None = None
|
|
20
|
+
self.token_expire_time: datetime | None = None
|
|
21
21
|
self._token_lock = threading.Lock()
|
|
22
22
|
|
|
23
23
|
self.feishu_base = feishu_base
|
|
24
24
|
self.table_app_token = table_app_token
|
|
25
25
|
self.table_id = table_id
|
|
26
26
|
|
|
27
|
-
def get_app_table_record_id(self, table_view_id: str, task_id: str) ->
|
|
27
|
+
def get_app_table_record_id(self, table_view_id: str, task_id: str) -> str | None:
|
|
28
28
|
"""
|
|
29
29
|
根据任务ID查询飞书多维表格记录,返回记录ID
|
|
30
30
|
"""
|
|
@@ -59,7 +59,7 @@ class FeishuTable:
|
|
|
59
59
|
logger.warning(f"查询 {task_id} 表格记录失败: {e}")
|
|
60
60
|
return None
|
|
61
61
|
|
|
62
|
-
def update_app_table_record(self, record_id: str, fields:
|
|
62
|
+
def update_app_table_record(self, record_id: str, fields: dict[str, Any]) -> bool:
|
|
63
63
|
"""
|
|
64
64
|
更新飞书多维表格记录
|
|
65
65
|
|
|
@@ -81,14 +81,14 @@ class FeishuTable:
|
|
|
81
81
|
logger.warning(f"更新表格记录失败: {result.get('msg')}")
|
|
82
82
|
return False
|
|
83
83
|
|
|
84
|
-
logger.
|
|
84
|
+
# logger.debug(f"成功更新记录ID {record_id},字段: {fields}")
|
|
85
85
|
return True
|
|
86
86
|
|
|
87
87
|
except Exception as e:
|
|
88
88
|
logger.warning(f"更新表格记录失败: {e}")
|
|
89
89
|
return False
|
|
90
90
|
|
|
91
|
-
def fetch_records(self, table_view_id: str, field_names: list[str], page_size: int = 100, page_token:
|
|
91
|
+
def fetch_records(self, table_view_id: str, field_names: list[str], page_size: int = 100, page_token: str | None = None) -> dict[str, Any]:
|
|
92
92
|
"""
|
|
93
93
|
获取表格记录
|
|
94
94
|
|
|
@@ -121,7 +121,7 @@ class FeishuTable:
|
|
|
121
121
|
logger.error(f"获取记录失败: {e}")
|
|
122
122
|
raise
|
|
123
123
|
|
|
124
|
-
def parse_record(self, record:
|
|
124
|
+
def parse_record(self, record: dict[str, Any], field_names: list[str] | None = None) -> dict[str, str]:
|
|
125
125
|
"""
|
|
126
126
|
解析单条记录,动态提取指定字段
|
|
127
127
|
|
|
@@ -157,7 +157,7 @@ class FeishuTable:
|
|
|
157
157
|
return result
|
|
158
158
|
|
|
159
159
|
def loop_all(
|
|
160
|
-
self, table_view_id: str, field_names: list[str], callback:
|
|
160
|
+
self, table_view_id: str, field_names: list[str], callback: Callable[[dict[str, str]], None] | None = None, limit: int | None = None
|
|
161
161
|
):
|
|
162
162
|
"""
|
|
163
163
|
遍历视图中的所有记录
|
|
@@ -222,3 +222,65 @@ class FeishuTable:
|
|
|
222
222
|
|
|
223
223
|
logger.info(f"总共获取到 {total_count} 条记录,成功处理 {processed_count} 条")
|
|
224
224
|
logger.info("数据遍历完成")
|
|
225
|
+
|
|
226
|
+
def fetch_all(self, table_view_id: str, field_names: list[str], limit: int | None = None) -> list[dict[str, str]]:
|
|
227
|
+
"""
|
|
228
|
+
抓取视图中的所有记录
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
limit: 可选的记录处理限制数量
|
|
232
|
+
"""
|
|
233
|
+
logger.info("开始获取飞书多维表格数据...")
|
|
234
|
+
|
|
235
|
+
page_count = 0
|
|
236
|
+
total_count = 0
|
|
237
|
+
processed_count = 0
|
|
238
|
+
page_token = None
|
|
239
|
+
|
|
240
|
+
records: list[dict[str, str]] = []
|
|
241
|
+
while True:
|
|
242
|
+
page_count += 1
|
|
243
|
+
logger.info(f"正在获取第 {page_count} 页数据...")
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
data = self.fetch_records(table_view_id, field_names, page_size=200, page_token=page_token)
|
|
247
|
+
items = data.get("items", [])
|
|
248
|
+
size = len(items)
|
|
249
|
+
total_count += size
|
|
250
|
+
page_token = data.get("page_token")
|
|
251
|
+
logger.info(f"第 {page_count} 页获取到 {size} 条记录,next page_token: {page_token}")
|
|
252
|
+
|
|
253
|
+
# 处理每条记录
|
|
254
|
+
for item in items:
|
|
255
|
+
logger.info(f"正在处理第 {processed_count + 1} 条数据...")
|
|
256
|
+
# 检查是否达到处理限制
|
|
257
|
+
if limit and processed_count >= limit:
|
|
258
|
+
logger.info(f"已达到处理限制 {limit},停止处理")
|
|
259
|
+
break
|
|
260
|
+
|
|
261
|
+
try:
|
|
262
|
+
parsed_record = self.parse_record(item)
|
|
263
|
+
processed_count += 1
|
|
264
|
+
|
|
265
|
+
logger.info(f"任务ID: {parsed_record['task_id']}")
|
|
266
|
+
records.append(parsed_record)
|
|
267
|
+
|
|
268
|
+
except Exception as e:
|
|
269
|
+
logger.error(f"处理记录失败: {e}, 记录: {item}")
|
|
270
|
+
continue
|
|
271
|
+
|
|
272
|
+
# 如果达到处理限制,退出外层循环
|
|
273
|
+
if limit and processed_count >= limit:
|
|
274
|
+
break
|
|
275
|
+
|
|
276
|
+
# 检查是否还有更多数据
|
|
277
|
+
if not data.get("has_more", False) or not page_token:
|
|
278
|
+
break
|
|
279
|
+
|
|
280
|
+
except Exception as e:
|
|
281
|
+
logger.error(f"获取第 {page_count} 页数据失败: {e}")
|
|
282
|
+
break
|
|
283
|
+
|
|
284
|
+
logger.info(f"总共获取到 {total_count} 条记录,成功处理 {processed_count} 条")
|
|
285
|
+
logger.info("数据遍历完成")
|
|
286
|
+
return records
|
dtsdance/spacex_bytedts.py
CHANGED
|
@@ -40,6 +40,41 @@ class SpaceXClient:
|
|
|
40
40
|
logger.warning(f"do quest queryServerMeta exception: {e}")
|
|
41
41
|
raise
|
|
42
42
|
|
|
43
|
+
def register_resource(self, site: str, data_raw: dict[str, Any]) -> bool:
|
|
44
|
+
site_info = self.bytecloud_client.get_site_config(site)
|
|
45
|
+
url = f"{site_info.endpoint_bytedts_spacex}/resource/v1/registerResource"
|
|
46
|
+
try:
|
|
47
|
+
response = requests.post(url, json=data_raw, headers=self.bytecloud_client.build_request_headers(site))
|
|
48
|
+
# print(f"response status code: {response.status_code}, response text: {response.text}")
|
|
49
|
+
|
|
50
|
+
response.raise_for_status()
|
|
51
|
+
|
|
52
|
+
result = response.json()
|
|
53
|
+
return result.get("message", "") == "ok"
|
|
54
|
+
|
|
55
|
+
except Exception as e:
|
|
56
|
+
logger.warning(f"do quest registerResource exception: {e}")
|
|
57
|
+
raise
|
|
58
|
+
|
|
59
|
+
def list_resources(self, site: str, data_raw: dict[str, Any]) -> list[str]:
|
|
60
|
+
site_info = self.bytecloud_client.get_site_config(site)
|
|
61
|
+
url = f"{site_info.endpoint_bytedts_spacex}/resource/v1/listResource"
|
|
62
|
+
try:
|
|
63
|
+
response = requests.post(url, json=data_raw, headers=self.bytecloud_client.build_request_headers(site))
|
|
64
|
+
# print(f"response status code: {response.status_code}, response text: {response.text}")
|
|
65
|
+
|
|
66
|
+
response.raise_for_status()
|
|
67
|
+
|
|
68
|
+
result = response.json()
|
|
69
|
+
if not result.get("message", "") == "ok":
|
|
70
|
+
return []
|
|
71
|
+
|
|
72
|
+
items = result.get("data", {}).get("items", [])
|
|
73
|
+
return [item["name"] for item in items]
|
|
74
|
+
except Exception as e:
|
|
75
|
+
logger.warning(f"do quest listResource exception: {e}")
|
|
76
|
+
raise
|
|
77
|
+
|
|
43
78
|
def register_gateway(self, site: str, gateway_info: GatewayInfo) -> bool:
|
|
44
79
|
site_info = self.bytecloud_client.get_site_config(site)
|
|
45
80
|
url = f"{site_info.endpoint_bytedts_spacex}/bytedts/v1/registryGateway"
|
|
@@ -71,3 +106,16 @@ class SpaceXClient:
|
|
|
71
106
|
except Exception as e:
|
|
72
107
|
logger.warning(f"do quest registryGateway exception: {e}")
|
|
73
108
|
raise
|
|
109
|
+
|
|
110
|
+
def gateway_operation(self, site: str, operation: str, data_raw: dict[str, Any]) -> dict[str, Any]:
|
|
111
|
+
site_info = self.bytecloud_client.get_site_config(site)
|
|
112
|
+
url = f"{site_info.endpoint_bytedts_spacex}/bytedts/v1/{operation}"
|
|
113
|
+
try:
|
|
114
|
+
response = requests.post(url, json=data_raw, headers=self.bytecloud_client.build_request_headers(site))
|
|
115
|
+
# print(f"response status code: {response.status_code}, response text: {response.text}")
|
|
116
|
+
|
|
117
|
+
response.raise_for_status()
|
|
118
|
+
return response.json()
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.warning(f"do quest gateway_operation exception: {e}")
|
|
121
|
+
raise
|
dts_dance-0.2.2.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
dtsdance/__init__.py,sha256=Yl_jEZ5weYfcrklnDvwB4wSgCOvMBLRRgWx0gHs3qfM,49
|
|
2
|
-
dtsdance/bytecloud.py,sha256=CQNebRy8UlILYmY8XhHhmEfW-WwW7SAlUh387X4OnY8,5646
|
|
3
|
-
dtsdance/dflow.py,sha256=XB6RClJzs9B5fhLofYvb5JazBF-iDfbtv1ETH6ENNUo,7074
|
|
4
|
-
dtsdance/dsyncer.py,sha256=3Oj1Ko5FuB_sUm9Hj-hBy95wee3b6TH2FXKoPFGsakM,11193
|
|
5
|
-
dtsdance/feishu_base.py,sha256=2j4ZM4PFqJ-9EhC6DQ1OmAg--3VBGZyyRuxyjL0j6OU,3733
|
|
6
|
-
dtsdance/feishu_table.py,sha256=ZUeoKrM4nmm5hFhc3vWOVYeLP390orm-284Od92G4iQ,8424
|
|
7
|
-
dtsdance/metrics_fe.py,sha256=hzIl5BJmuCrkqJOHELVzXm3YAqrPttbyVkKBglS4mgQ,18978
|
|
8
|
-
dtsdance/s3.py,sha256=Bh-cwLksfO5PewNtIzE_Md3rRLDLI1DUVoOD7Pou5T8,1294
|
|
9
|
-
dtsdance/spacex_bytedts.py,sha256=83lUU9sFPsvmZ0zLCGG_V6vMYXePKbEUeG1d6qfkQhE,2575
|
|
10
|
-
dtsdance/tcc_inner.py,sha256=6Tuq_r2nNCK_HC4hqEGh7UVAa8kDtuIcU95WBu4zuFQ,1623
|
|
11
|
-
dtsdance/tcc_open.py,sha256=Qb_ue3xH0CSsoReItdFKuvW7JsDTfFkDNIB_4zjzSQI,6893
|
|
12
|
-
dts_dance-0.2.2.dist-info/METADATA,sha256=ZRzPIxPE0Y4uJRTwBK2_PukFRUBuHb8xkuxQPGQnOjo,793
|
|
13
|
-
dts_dance-0.2.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
14
|
-
dts_dance-0.2.2.dist-info/RECORD,,
|
|
File without changes
|