robot-wrapper-sdk 0.2.5__tar.gz → 0.2.7__tar.gz
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.
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/PKG-INFO +1 -1
- robot_wrapper_sdk-0.2.7/examples/main.py +80 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/pyproject.toml +1 -1
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_sdk/infrastructure/api_client.py +80 -21
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_sdk/infrastructure/robot_api_repository.py +33 -8
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_wrapper_sdk.egg-info/PKG-INFO +1 -1
- robot_wrapper_sdk-0.2.5/examples/main.py +0 -42
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/README.md +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_sdk/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_sdk/application/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_sdk/application/usecases.py +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_sdk/domain/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_sdk/domain/entities.py +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_sdk/domain/repositories.py +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_sdk/infrastructure/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_wrapper_sdk.egg-info/SOURCES.txt +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_wrapper_sdk.egg-info/dependency_links.txt +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_wrapper_sdk.egg-info/requires.txt +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_wrapper_sdk.egg-info/top_level.txt +0 -0
- {robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/setup.cfg +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
6
|
+
from robot_sdk import RobotPlatformModule, AsyncRobotPlatformModule
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def setup_environ():
|
|
10
|
+
# Update theo develop-app auth flow
|
|
11
|
+
os.environ["ROBOT_PLATFORM_BASE_URL"] = "http://localhost:8085"
|
|
12
|
+
os.environ["ROBOT_PLATFORM_APP_ID"] = "your_app_id"
|
|
13
|
+
os.environ["ROBOT_PLATFORM_APP_SECRET"] = "your_app_secret"
|
|
14
|
+
# os.environ["ROBOT_PLATFORM_PROXY_URL"] = "socks5h://192.168.3.100:1080"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_sync():
|
|
18
|
+
print("--- SYNC EXECUTION ---")
|
|
19
|
+
module = RobotPlatformModule()
|
|
20
|
+
try:
|
|
21
|
+
robot_id = "2047631542552334336"
|
|
22
|
+
|
|
23
|
+
robot = module.get_robot(robot_id)
|
|
24
|
+
if robot:
|
|
25
|
+
print("Robot:", robot.username, robot.platform)
|
|
26
|
+
else:
|
|
27
|
+
print("Robot not found")
|
|
28
|
+
|
|
29
|
+
login_tasks = module.acquire_need_login(limit=20, lock_minutes=30)
|
|
30
|
+
print("Acquire login tasks:", len(login_tasks))
|
|
31
|
+
|
|
32
|
+
module.update_auth_status(robot_id, "authorized")
|
|
33
|
+
print("Updated auth_status -> authorized")
|
|
34
|
+
|
|
35
|
+
hardening_tasks = module.acquire_unhardened(limit=20, lock_minutes=30, min_age_days=0)
|
|
36
|
+
print("Acquire hardening tasks:", len(hardening_tasks))
|
|
37
|
+
|
|
38
|
+
module.update_security_hardened(robot_id, True)
|
|
39
|
+
print("Updated security_hardened -> true")
|
|
40
|
+
|
|
41
|
+
except Exception as e:
|
|
42
|
+
print("Sync demo error:", e)
|
|
43
|
+
finally:
|
|
44
|
+
module.close()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
async def test_async():
|
|
48
|
+
print("--- ASYNC EXECUTION ---")
|
|
49
|
+
module = AsyncRobotPlatformModule()
|
|
50
|
+
try:
|
|
51
|
+
robot_id = "2047631542552334336"
|
|
52
|
+
|
|
53
|
+
robot = await module.get_robot(robot_id)
|
|
54
|
+
if robot:
|
|
55
|
+
print("Robot:", robot.username, robot.platform)
|
|
56
|
+
else:
|
|
57
|
+
print("Robot not found")
|
|
58
|
+
|
|
59
|
+
login_tasks = await module.acquire_need_login(limit=20, lock_minutes=30)
|
|
60
|
+
print("Acquire login tasks:", len(login_tasks))
|
|
61
|
+
|
|
62
|
+
await module.update_auth_status(robot_id, "authorized")
|
|
63
|
+
print("Updated auth_status -> authorized")
|
|
64
|
+
|
|
65
|
+
hardening_tasks = await module.acquire_unhardened(limit=20, lock_minutes=30, min_age_days=0)
|
|
66
|
+
print("Acquire hardening tasks:", len(hardening_tasks))
|
|
67
|
+
|
|
68
|
+
await module.update_security_hardened(robot_id, True)
|
|
69
|
+
print("Updated security_hardened -> true")
|
|
70
|
+
|
|
71
|
+
except Exception as e:
|
|
72
|
+
print("Async demo error:", e)
|
|
73
|
+
finally:
|
|
74
|
+
await module.close()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
setup_environ()
|
|
79
|
+
test_sync()
|
|
80
|
+
asyncio.run(test_async())
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import httpx
|
|
2
2
|
import os
|
|
3
3
|
from typing import Dict, Any, Optional
|
|
4
|
+
from httpx import RemoteProtocolError
|
|
5
|
+
|
|
6
|
+
def _extract_tokens(payload: Dict[str, Any]) -> tuple[Optional[str], Optional[str]]:
|
|
7
|
+
data = payload.get("data") if isinstance(payload, dict) else None
|
|
8
|
+
if isinstance(data, dict):
|
|
9
|
+
access_token = data.get("access_token")
|
|
10
|
+
refresh_token = data.get("refresh_token")
|
|
11
|
+
else:
|
|
12
|
+
access_token = payload.get("access_token") if isinstance(payload, dict) else None
|
|
13
|
+
refresh_token = payload.get("refresh_token") if isinstance(payload, dict) else None
|
|
14
|
+
|
|
15
|
+
access_token = str(access_token).strip() if access_token else None
|
|
16
|
+
refresh_token = str(refresh_token).strip() if refresh_token else None
|
|
17
|
+
return access_token, refresh_token
|
|
4
18
|
|
|
5
19
|
class RobotAuth(httpx.Auth):
|
|
6
20
|
def __init__(self, login_func, refresh_func):
|
|
@@ -9,11 +23,15 @@ class RobotAuth(httpx.Auth):
|
|
|
9
23
|
|
|
10
24
|
def auth_flow(self, request):
|
|
11
25
|
token = self.login_func()
|
|
26
|
+
if not token:
|
|
27
|
+
raise RuntimeError("Missing access token. Authenticate first.")
|
|
12
28
|
request.headers["Authorization"] = f"Bearer {token}"
|
|
13
29
|
response = yield request
|
|
14
30
|
|
|
15
31
|
if response.status_code == 401:
|
|
16
32
|
token = self.refresh_func()
|
|
33
|
+
if not token:
|
|
34
|
+
raise RuntimeError("Token refresh failed: empty access token")
|
|
17
35
|
request.headers["Authorization"] = f"Bearer {token}"
|
|
18
36
|
yield request
|
|
19
37
|
|
|
@@ -24,11 +42,15 @@ class AsyncRobotAuth(httpx.Auth):
|
|
|
24
42
|
|
|
25
43
|
async def async_auth_flow(self, request):
|
|
26
44
|
token = await self.login_func()
|
|
45
|
+
if not token:
|
|
46
|
+
raise RuntimeError("Missing access token. Authenticate first.")
|
|
27
47
|
request.headers["Authorization"] = f"Bearer {token}"
|
|
28
48
|
response = yield request
|
|
29
49
|
|
|
30
50
|
if response.status_code == 401:
|
|
31
51
|
token = await self.refresh_func()
|
|
52
|
+
if not token:
|
|
53
|
+
raise RuntimeError("Token refresh failed: empty access token")
|
|
32
54
|
request.headers["Authorization"] = f"Bearer {token}"
|
|
33
55
|
yield request
|
|
34
56
|
|
|
@@ -56,7 +78,10 @@ class HTTPClient:
|
|
|
56
78
|
def _get_or_login(self) -> str:
|
|
57
79
|
if not self.access_token:
|
|
58
80
|
self._login()
|
|
59
|
-
|
|
81
|
+
token = str(self.access_token).strip() if self.access_token else ""
|
|
82
|
+
if not token:
|
|
83
|
+
raise RuntimeError("Empty access token after login")
|
|
84
|
+
return token
|
|
60
85
|
|
|
61
86
|
def _login(self) -> None:
|
|
62
87
|
with httpx.Client(proxy=self.proxy_url) as c:
|
|
@@ -67,8 +92,7 @@ class HTTPClient:
|
|
|
67
92
|
resp.raise_for_status()
|
|
68
93
|
try:
|
|
69
94
|
data = resp.json()
|
|
70
|
-
self.access_token = data
|
|
71
|
-
self.refresh_token = data.get("refresh_token")
|
|
95
|
+
self.access_token, self.refresh_token = _extract_tokens(data)
|
|
72
96
|
except Exception as e:
|
|
73
97
|
print(f"❌ Failed to parse JSON from _login: {e}")
|
|
74
98
|
print(f"📄 Login Response Content: {resp.text[:500]}")
|
|
@@ -78,7 +102,10 @@ class HTTPClient:
|
|
|
78
102
|
# Developer tokens currently don't use refresh flow in the same way, but keeping structure
|
|
79
103
|
if not self.refresh_token:
|
|
80
104
|
self._login()
|
|
81
|
-
|
|
105
|
+
token = str(self.access_token).strip() if self.access_token else ""
|
|
106
|
+
if not token:
|
|
107
|
+
raise RuntimeError("Empty access token after login")
|
|
108
|
+
return token
|
|
82
109
|
|
|
83
110
|
with httpx.Client(proxy=self.proxy_url) as c:
|
|
84
111
|
resp = c.post(
|
|
@@ -89,22 +116,47 @@ class HTTPClient:
|
|
|
89
116
|
self._login()
|
|
90
117
|
else:
|
|
91
118
|
data = resp.json()
|
|
92
|
-
self.access_token = data
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
119
|
+
self.access_token, self.refresh_token = _extract_tokens(data)
|
|
120
|
+
|
|
121
|
+
token = str(self.access_token).strip() if self.access_token else ""
|
|
122
|
+
if not token:
|
|
123
|
+
raise RuntimeError("Token refresh failed: empty access token")
|
|
124
|
+
return token
|
|
96
125
|
|
|
97
126
|
def request(self, method: str, path: str, **kwargs: Any) -> Dict[str, Any]:
|
|
98
|
-
# Intelligent path prefixing
|
|
99
127
|
full_path = path
|
|
100
|
-
if
|
|
101
|
-
|
|
128
|
+
if path.startswith("/api/"):
|
|
129
|
+
full_path = path
|
|
130
|
+
else:
|
|
102
131
|
if not path.startswith("/"):
|
|
103
132
|
path = f"/{path}"
|
|
104
133
|
full_path = f"/api/v1/developer{path}"
|
|
105
|
-
|
|
134
|
+
|
|
106
135
|
print(f"🚀 Requesting: {self.base_url}{full_path}")
|
|
107
|
-
|
|
136
|
+
last_err: Optional[Exception] = None
|
|
137
|
+
resp = None
|
|
138
|
+
for attempt in range(2):
|
|
139
|
+
try:
|
|
140
|
+
resp = self.client.request(method, full_path, **kwargs)
|
|
141
|
+
break
|
|
142
|
+
except Exception as err:
|
|
143
|
+
msg = str(err)
|
|
144
|
+
is_disconnect = isinstance(err, RemoteProtocolError) or "Server disconnected without sending a response" in msg
|
|
145
|
+
if not is_disconnect or attempt == 1:
|
|
146
|
+
raise
|
|
147
|
+
last_err = err
|
|
148
|
+
self.client.close()
|
|
149
|
+
self.client = httpx.Client(
|
|
150
|
+
base_url=self.base_url,
|
|
151
|
+
auth=RobotAuth(self._get_or_login, self._refresh),
|
|
152
|
+
proxy=self.proxy_url,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
if resp is None:
|
|
156
|
+
if last_err is not None:
|
|
157
|
+
raise last_err
|
|
158
|
+
raise RuntimeError("Request failed without response")
|
|
159
|
+
|
|
108
160
|
resp.raise_for_status()
|
|
109
161
|
try:
|
|
110
162
|
return dict(resp.json())
|
|
@@ -140,7 +192,10 @@ class AsyncHTTPClient:
|
|
|
140
192
|
async def _get_or_login(self) -> str:
|
|
141
193
|
if not self.access_token:
|
|
142
194
|
await self._login()
|
|
143
|
-
|
|
195
|
+
token = str(self.access_token).strip() if self.access_token else ""
|
|
196
|
+
if not token:
|
|
197
|
+
raise RuntimeError("Empty access token after login")
|
|
198
|
+
return token
|
|
144
199
|
|
|
145
200
|
async def _login(self) -> None:
|
|
146
201
|
async with httpx.AsyncClient(proxy=self.proxy_url) as c:
|
|
@@ -151,8 +206,7 @@ class AsyncHTTPClient:
|
|
|
151
206
|
resp.raise_for_status()
|
|
152
207
|
try:
|
|
153
208
|
data = resp.json()
|
|
154
|
-
self.access_token = data
|
|
155
|
-
self.refresh_token = data.get("refresh_token")
|
|
209
|
+
self.access_token, self.refresh_token = _extract_tokens(data)
|
|
156
210
|
except Exception as e:
|
|
157
211
|
print(f"❌ Failed to parse JSON from async _login: {e}")
|
|
158
212
|
print(f"📄 Login Response Content: {resp.text[:500]}")
|
|
@@ -161,7 +215,10 @@ class AsyncHTTPClient:
|
|
|
161
215
|
async def _refresh(self) -> str:
|
|
162
216
|
if not self.refresh_token:
|
|
163
217
|
await self._login()
|
|
164
|
-
|
|
218
|
+
token = str(self.access_token).strip() if self.access_token else ""
|
|
219
|
+
if not token:
|
|
220
|
+
raise RuntimeError("Empty access token after login")
|
|
221
|
+
return token
|
|
165
222
|
|
|
166
223
|
async with httpx.AsyncClient(proxy=self.proxy_url) as c:
|
|
167
224
|
resp = await c.post(
|
|
@@ -172,10 +229,12 @@ class AsyncHTTPClient:
|
|
|
172
229
|
await self._login()
|
|
173
230
|
else:
|
|
174
231
|
data = resp.json()
|
|
175
|
-
self.access_token = data
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
232
|
+
self.access_token, self.refresh_token = _extract_tokens(data)
|
|
233
|
+
|
|
234
|
+
token = str(self.access_token).strip() if self.access_token else ""
|
|
235
|
+
if not token:
|
|
236
|
+
raise RuntimeError("Token refresh failed: empty access token")
|
|
237
|
+
return token
|
|
179
238
|
|
|
180
239
|
async def request(self, method: str, path: str, **kwargs: Any) -> Dict[str, Any]:
|
|
181
240
|
# Intelligent path prefixing
|
{robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_sdk/infrastructure/robot_api_repository.py
RENAMED
|
@@ -3,6 +3,33 @@ from .api_client import HTTPClient, AsyncHTTPClient
|
|
|
3
3
|
from ..domain.repositories import RobotRepository, AsyncRobotRepository
|
|
4
4
|
from ..domain.entities import Robot, RobotSecrets
|
|
5
5
|
|
|
6
|
+
|
|
7
|
+
def _extract_list_payload(resp: Dict[str, Any]) -> Tuple[List[Dict[str, Any]], int]:
|
|
8
|
+
container = resp.get("data") if isinstance(resp, dict) else None
|
|
9
|
+
if isinstance(container, dict):
|
|
10
|
+
items = container.get("data")
|
|
11
|
+
total = container.get("total", 0)
|
|
12
|
+
else:
|
|
13
|
+
items = container
|
|
14
|
+
total = resp.get("total", 0) if isinstance(resp, dict) else 0
|
|
15
|
+
|
|
16
|
+
if not isinstance(items, list):
|
|
17
|
+
return [], int(total) if isinstance(total, int) else 0
|
|
18
|
+
|
|
19
|
+
mapped = [item for item in items if isinstance(item, dict)]
|
|
20
|
+
return mapped, int(total) if isinstance(total, int) else 0
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _extract_items(resp: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
24
|
+
container = resp.get("data") if isinstance(resp, dict) else None
|
|
25
|
+
if isinstance(container, list):
|
|
26
|
+
return [item for item in container if isinstance(item, dict)]
|
|
27
|
+
if isinstance(container, dict):
|
|
28
|
+
nested = container.get("data")
|
|
29
|
+
if isinstance(nested, list):
|
|
30
|
+
return [item for item in nested if isinstance(item, dict)]
|
|
31
|
+
return []
|
|
32
|
+
|
|
6
33
|
class RobotAPIRepository(RobotRepository):
|
|
7
34
|
def __init__(self, client: HTTPClient):
|
|
8
35
|
self.client = client
|
|
@@ -28,8 +55,7 @@ class RobotAPIRepository(RobotRepository):
|
|
|
28
55
|
if project_id: params["project_id"] = project_id
|
|
29
56
|
|
|
30
57
|
resp = self.client.request("GET", "/robots", params=params)
|
|
31
|
-
data = resp
|
|
32
|
-
total = resp.get("total", 0)
|
|
58
|
+
data, total = _extract_list_payload(resp)
|
|
33
59
|
return [Robot(**r) for r in data], total
|
|
34
60
|
|
|
35
61
|
def acquire_need_login(self, limit: int = 20, lock_minutes: int = 30) -> List[Robot]:
|
|
@@ -38,7 +64,7 @@ class RobotAPIRepository(RobotRepository):
|
|
|
38
64
|
"/robots/login/acquire",
|
|
39
65
|
json={"limit": limit, "lock_minutes": lock_minutes},
|
|
40
66
|
)
|
|
41
|
-
data = resp
|
|
67
|
+
data = _extract_items(resp)
|
|
42
68
|
return [Robot(**r) for r in data]
|
|
43
69
|
|
|
44
70
|
def acquire_unhardened(self, limit: int = 20, lock_minutes: int = 30, min_age_days: int = 0) -> List[Robot]:
|
|
@@ -47,7 +73,7 @@ class RobotAPIRepository(RobotRepository):
|
|
|
47
73
|
"/robots/security-hardened/acquire",
|
|
48
74
|
json={"limit": limit, "lock_minutes": lock_minutes, "min_age_days": min_age_days},
|
|
49
75
|
)
|
|
50
|
-
data = resp
|
|
76
|
+
data = _extract_items(resp)
|
|
51
77
|
return [Robot(**r) for r in data]
|
|
52
78
|
|
|
53
79
|
def update_auth_status(self, robot_id: str, auth_status: str) -> None:
|
|
@@ -89,8 +115,7 @@ class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
|
89
115
|
if project_id: params["project_id"] = project_id
|
|
90
116
|
|
|
91
117
|
resp = await self.client.request("GET", "/robots", params=params)
|
|
92
|
-
data = resp
|
|
93
|
-
total = resp.get("total", 0)
|
|
118
|
+
data, total = _extract_list_payload(resp)
|
|
94
119
|
return [Robot(**r) for r in data], total
|
|
95
120
|
|
|
96
121
|
async def acquire_need_login(self, limit: int = 20, lock_minutes: int = 30) -> List[Robot]:
|
|
@@ -99,7 +124,7 @@ class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
|
99
124
|
"/robots/login/acquire",
|
|
100
125
|
json={"limit": limit, "lock_minutes": lock_minutes},
|
|
101
126
|
)
|
|
102
|
-
data = resp
|
|
127
|
+
data = _extract_items(resp)
|
|
103
128
|
return [Robot(**r) for r in data]
|
|
104
129
|
|
|
105
130
|
async def acquire_unhardened(self, limit: int = 20, lock_minutes: int = 30, min_age_days: int = 0) -> List[Robot]:
|
|
@@ -108,7 +133,7 @@ class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
|
108
133
|
"/robots/security-hardened/acquire",
|
|
109
134
|
json={"limit": limit, "lock_minutes": lock_minutes, "min_age_days": min_age_days},
|
|
110
135
|
)
|
|
111
|
-
data = resp
|
|
136
|
+
data = _extract_items(resp)
|
|
112
137
|
return [Robot(**r) for r in data]
|
|
113
138
|
|
|
114
139
|
async def update_auth_status(self, robot_id: str, auth_status: str) -> None:
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import os
|
|
3
|
-
import sys
|
|
4
|
-
|
|
5
|
-
# Mở rộng đường dẫn tránh lỗi module khi chạy local
|
|
6
|
-
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
7
|
-
from robot_sdk import RobotPlatformModule, AsyncRobotPlatformModule
|
|
8
|
-
|
|
9
|
-
def setup_environ():
|
|
10
|
-
os.environ["ROBOT_PLATFORM_BASE_URL"] = "http://localhost:8080"
|
|
11
|
-
os.environ["ROBOT_PLATFORM_USERNAME"] = "testuser"
|
|
12
|
-
os.environ["ROBOT_PLATFORM_PASSWORD"] = "testpass"
|
|
13
|
-
|
|
14
|
-
def test_sync():
|
|
15
|
-
"""Ví dụ sử dụng thư viện đồng bộ."""
|
|
16
|
-
print("--- SYNC EXECUTION ---")
|
|
17
|
-
module = RobotPlatformModule()
|
|
18
|
-
try:
|
|
19
|
-
robot = module.robot_usecase.get_robot_profile("1234")
|
|
20
|
-
print("Tải thông tin thành công:", robot.username)
|
|
21
|
-
except Exception as e:
|
|
22
|
-
print("Lỗi Demo:", e)
|
|
23
|
-
finally:
|
|
24
|
-
module.close()
|
|
25
|
-
|
|
26
|
-
async def test_async():
|
|
27
|
-
"""Ví dụ sử dụng thư viện bất đồng bộ."""
|
|
28
|
-
print("--- ASYNC EXECUTION ---")
|
|
29
|
-
module = AsyncRobotPlatformModule()
|
|
30
|
-
try:
|
|
31
|
-
robot = await module.robot_usecase.get_robot_profile("1234")
|
|
32
|
-
print("Tải thông tin thành công:", robot.username)
|
|
33
|
-
except Exception as e:
|
|
34
|
-
print("Lỗi Demo:", e)
|
|
35
|
-
finally:
|
|
36
|
-
await module.close()
|
|
37
|
-
|
|
38
|
-
if __name__ == "__main__":
|
|
39
|
-
setup_environ()
|
|
40
|
-
|
|
41
|
-
test_sync()
|
|
42
|
-
asyncio.run(test_async())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_wrapper_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{robot_wrapper_sdk-0.2.5 → robot_wrapper_sdk-0.2.7}/robot_wrapper_sdk.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|