robot-wrapper-sdk 0.2.7__tar.gz → 0.2.8__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.7 → robot_wrapper_sdk-0.2.8}/PKG-INFO +19 -8
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/README.md +18 -7
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/pyproject.toml +1 -1
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_sdk/__init__.py +19 -6
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_sdk/application/usecases.py +11 -5
- robot_wrapper_sdk-0.2.8/robot_sdk/domain/entities.py +118 -0
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_sdk/domain/repositories.py +13 -5
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_sdk/infrastructure/robot_api_repository.py +40 -9
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_wrapper_sdk.egg-info/PKG-INFO +19 -8
- robot_wrapper_sdk-0.2.7/robot_sdk/domain/entities.py +0 -51
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/examples/main.py +0 -0
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_sdk/application/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_sdk/domain/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_sdk/infrastructure/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_sdk/infrastructure/api_client.py +0 -0
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_wrapper_sdk.egg-info/SOURCES.txt +0 -0
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_wrapper_sdk.egg-info/dependency_links.txt +0 -0
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_wrapper_sdk.egg-info/requires.txt +0 -0
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_wrapper_sdk.egg-info/top_level.txt +0 -0
- {robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: robot-wrapper-sdk
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: Robot Platform API SDK
|
|
5
5
|
Author-email: GH Robot Platform Team <team@ghrobot.com>
|
|
6
6
|
License: MIT
|
|
@@ -38,7 +38,7 @@ Or pass values directly when creating the module.
|
|
|
38
38
|
## Quick Start (Sync)
|
|
39
39
|
|
|
40
40
|
```python
|
|
41
|
-
from robot_sdk import RobotPlatformModule
|
|
41
|
+
from robot_sdk import RobotPlatformModule, RobotStatus, RobotAuthStatus
|
|
42
42
|
|
|
43
43
|
sdk = RobotPlatformModule(
|
|
44
44
|
base_url="http://localhost:8085",
|
|
@@ -51,14 +51,14 @@ sdk = RobotPlatformModule(
|
|
|
51
51
|
robot = sdk.get_robot("2047631542552334336")
|
|
52
52
|
print(robot.platform if robot else "not found")
|
|
53
53
|
|
|
54
|
-
# Update lifecycle status
|
|
55
|
-
sdk.update_status("2047631542552334336",
|
|
54
|
+
# Update lifecycle status (prefer enum)
|
|
55
|
+
sdk.update_status("2047631542552334336", RobotStatus.LIVE)
|
|
56
56
|
|
|
57
57
|
# Acquire login tasks
|
|
58
58
|
login_tasks = sdk.acquire_need_login(limit=20, lock_minutes=30)
|
|
59
59
|
|
|
60
|
-
# Update auth status after worker result
|
|
61
|
-
sdk.update_auth_status("2047631542552334336",
|
|
60
|
+
# Update auth status after worker result (prefer enum)
|
|
61
|
+
sdk.update_auth_status("2047631542552334336", RobotAuthStatus.AUTHORIZED)
|
|
62
62
|
# allowed values: authorized | unauthorized | logged_out
|
|
63
63
|
|
|
64
64
|
# Acquire hardening tasks
|
|
@@ -67,6 +67,12 @@ hardening_tasks = sdk.acquire_unhardened(limit=20, lock_minutes=30, min_age_days
|
|
|
67
67
|
# Update hardening status after worker result
|
|
68
68
|
sdk.update_security_hardened("2047631542552334336", True)
|
|
69
69
|
|
|
70
|
+
# Update metadata (partial patch)
|
|
71
|
+
sdk.update_metadata("2047631542552334336", {
|
|
72
|
+
"country_code": "VN",
|
|
73
|
+
"note": "updated by sdk"
|
|
74
|
+
})
|
|
75
|
+
|
|
70
76
|
sdk.close()
|
|
71
77
|
```
|
|
72
78
|
|
|
@@ -74,7 +80,7 @@ sdk.close()
|
|
|
74
80
|
|
|
75
81
|
```python
|
|
76
82
|
import asyncio
|
|
77
|
-
from robot_sdk import AsyncRobotPlatformModule
|
|
83
|
+
from robot_sdk import AsyncRobotPlatformModule, RobotAuthStatus
|
|
78
84
|
|
|
79
85
|
async def main():
|
|
80
86
|
sdk = AsyncRobotPlatformModule(
|
|
@@ -86,8 +92,12 @@ async def main():
|
|
|
86
92
|
robot = await sdk.get_robot("2047631542552334336")
|
|
87
93
|
print(robot.platform if robot else "not found")
|
|
88
94
|
|
|
89
|
-
await sdk.update_auth_status("2047631542552334336",
|
|
95
|
+
await sdk.update_auth_status("2047631542552334336", RobotAuthStatus.AUTHORIZED)
|
|
90
96
|
await sdk.update_security_hardened("2047631542552334336", True)
|
|
97
|
+
await sdk.update_metadata("2047631542552334336", {
|
|
98
|
+
"country_code": "VN",
|
|
99
|
+
"note": "updated by async sdk"
|
|
100
|
+
})
|
|
91
101
|
|
|
92
102
|
await sdk.close()
|
|
93
103
|
|
|
@@ -145,6 +155,7 @@ Update endpoints return:
|
|
|
145
155
|
- `acquire_unhardened(limit=20, lock_minutes=30, min_age_days=0)`
|
|
146
156
|
- `update_auth_status(robot_id, auth_status)`
|
|
147
157
|
- `update_security_hardened(robot_id, security_hardened)`
|
|
158
|
+
- `update_metadata(robot_id, metadata)`
|
|
148
159
|
- `close()`
|
|
149
160
|
|
|
150
161
|
### `AsyncRobotPlatformModule` (async)
|
|
@@ -28,7 +28,7 @@ Or pass values directly when creating the module.
|
|
|
28
28
|
## Quick Start (Sync)
|
|
29
29
|
|
|
30
30
|
```python
|
|
31
|
-
from robot_sdk import RobotPlatformModule
|
|
31
|
+
from robot_sdk import RobotPlatformModule, RobotStatus, RobotAuthStatus
|
|
32
32
|
|
|
33
33
|
sdk = RobotPlatformModule(
|
|
34
34
|
base_url="http://localhost:8085",
|
|
@@ -41,14 +41,14 @@ sdk = RobotPlatformModule(
|
|
|
41
41
|
robot = sdk.get_robot("2047631542552334336")
|
|
42
42
|
print(robot.platform if robot else "not found")
|
|
43
43
|
|
|
44
|
-
# Update lifecycle status
|
|
45
|
-
sdk.update_status("2047631542552334336",
|
|
44
|
+
# Update lifecycle status (prefer enum)
|
|
45
|
+
sdk.update_status("2047631542552334336", RobotStatus.LIVE)
|
|
46
46
|
|
|
47
47
|
# Acquire login tasks
|
|
48
48
|
login_tasks = sdk.acquire_need_login(limit=20, lock_minutes=30)
|
|
49
49
|
|
|
50
|
-
# Update auth status after worker result
|
|
51
|
-
sdk.update_auth_status("2047631542552334336",
|
|
50
|
+
# Update auth status after worker result (prefer enum)
|
|
51
|
+
sdk.update_auth_status("2047631542552334336", RobotAuthStatus.AUTHORIZED)
|
|
52
52
|
# allowed values: authorized | unauthorized | logged_out
|
|
53
53
|
|
|
54
54
|
# Acquire hardening tasks
|
|
@@ -57,6 +57,12 @@ hardening_tasks = sdk.acquire_unhardened(limit=20, lock_minutes=30, min_age_days
|
|
|
57
57
|
# Update hardening status after worker result
|
|
58
58
|
sdk.update_security_hardened("2047631542552334336", True)
|
|
59
59
|
|
|
60
|
+
# Update metadata (partial patch)
|
|
61
|
+
sdk.update_metadata("2047631542552334336", {
|
|
62
|
+
"country_code": "VN",
|
|
63
|
+
"note": "updated by sdk"
|
|
64
|
+
})
|
|
65
|
+
|
|
60
66
|
sdk.close()
|
|
61
67
|
```
|
|
62
68
|
|
|
@@ -64,7 +70,7 @@ sdk.close()
|
|
|
64
70
|
|
|
65
71
|
```python
|
|
66
72
|
import asyncio
|
|
67
|
-
from robot_sdk import AsyncRobotPlatformModule
|
|
73
|
+
from robot_sdk import AsyncRobotPlatformModule, RobotAuthStatus
|
|
68
74
|
|
|
69
75
|
async def main():
|
|
70
76
|
sdk = AsyncRobotPlatformModule(
|
|
@@ -76,8 +82,12 @@ async def main():
|
|
|
76
82
|
robot = await sdk.get_robot("2047631542552334336")
|
|
77
83
|
print(robot.platform if robot else "not found")
|
|
78
84
|
|
|
79
|
-
await sdk.update_auth_status("2047631542552334336",
|
|
85
|
+
await sdk.update_auth_status("2047631542552334336", RobotAuthStatus.AUTHORIZED)
|
|
80
86
|
await sdk.update_security_hardened("2047631542552334336", True)
|
|
87
|
+
await sdk.update_metadata("2047631542552334336", {
|
|
88
|
+
"country_code": "VN",
|
|
89
|
+
"note": "updated by async sdk"
|
|
90
|
+
})
|
|
81
91
|
|
|
82
92
|
await sdk.close()
|
|
83
93
|
|
|
@@ -135,6 +145,7 @@ Update endpoints return:
|
|
|
135
145
|
- `acquire_unhardened(limit=20, lock_minutes=30, min_age_days=0)`
|
|
136
146
|
- `update_auth_status(robot_id, auth_status)`
|
|
137
147
|
- `update_security_hardened(robot_id, security_hardened)`
|
|
148
|
+
- `update_metadata(robot_id, metadata)`
|
|
138
149
|
- `close()`
|
|
139
150
|
|
|
140
151
|
### `AsyncRobotPlatformModule` (async)
|
|
@@ -2,7 +2,7 @@ from typing import Optional, List, Dict, Any, Tuple
|
|
|
2
2
|
from .infrastructure.api_client import HTTPClient, AsyncHTTPClient
|
|
3
3
|
from .infrastructure.robot_api_repository import RobotAPIRepository, AsyncRobotAPIRepository
|
|
4
4
|
from .application.usecases import RobotUsecase, AsyncRobotUsecase
|
|
5
|
-
from .domain.entities import Robot, RobotSecrets
|
|
5
|
+
from .domain.entities import Robot, RobotSecrets, RobotStatus, RobotAuthStatus
|
|
6
6
|
|
|
7
7
|
__version__ = "0.2.1"
|
|
8
8
|
|
|
@@ -28,7 +28,7 @@ class RobotPlatformModule:
|
|
|
28
28
|
def get_secrets(self, robot_id: str) -> Optional[RobotSecrets]:
|
|
29
29
|
return self.robot_usecase.get_secrets(robot_id)
|
|
30
30
|
|
|
31
|
-
def update_status(self, robot_id: str, status: str) -> None:
|
|
31
|
+
def update_status(self, robot_id: str, status: str | RobotStatus) -> None:
|
|
32
32
|
self.robot_usecase.update_status(robot_id, status)
|
|
33
33
|
|
|
34
34
|
def acquire_need_login(self, limit: int = 20, lock_minutes: int = 30):
|
|
@@ -37,12 +37,15 @@ class RobotPlatformModule:
|
|
|
37
37
|
def acquire_unhardened(self, limit: int = 20, lock_minutes: int = 30, min_age_days: int = 0):
|
|
38
38
|
return self.robot_usecase.acquire_unhardened(limit, lock_minutes, min_age_days)
|
|
39
39
|
|
|
40
|
-
def update_auth_status(self, robot_id: str, auth_status: str) -> None:
|
|
40
|
+
def update_auth_status(self, robot_id: str, auth_status: str | RobotAuthStatus) -> None:
|
|
41
41
|
self.robot_usecase.update_auth_status(robot_id, auth_status)
|
|
42
42
|
|
|
43
43
|
def update_security_hardened(self, robot_id: str, security_hardened: bool) -> None:
|
|
44
44
|
self.robot_usecase.update_security_hardened(robot_id, security_hardened)
|
|
45
45
|
|
|
46
|
+
def update_metadata(self, robot_id: str, metadata: Dict[str, Any]) -> None:
|
|
47
|
+
self.robot_usecase.update_metadata(robot_id, metadata)
|
|
48
|
+
|
|
46
49
|
|
|
47
50
|
class AsyncRobotPlatformModule:
|
|
48
51
|
"""Asynchronous Facade for the Robot Platform SDK."""
|
|
@@ -66,7 +69,7 @@ class AsyncRobotPlatformModule:
|
|
|
66
69
|
async def get_secrets(self, robot_id: str) -> Optional[RobotSecrets]:
|
|
67
70
|
return await self.robot_usecase.get_secrets(robot_id)
|
|
68
71
|
|
|
69
|
-
async def update_status(self, robot_id: str, status: str) -> None:
|
|
72
|
+
async def update_status(self, robot_id: str, status: str | RobotStatus) -> None:
|
|
70
73
|
await self.robot_usecase.update_status(robot_id, status)
|
|
71
74
|
|
|
72
75
|
async def acquire_need_login(self, limit: int = 20, lock_minutes: int = 30):
|
|
@@ -75,10 +78,20 @@ class AsyncRobotPlatformModule:
|
|
|
75
78
|
async def acquire_unhardened(self, limit: int = 20, lock_minutes: int = 30, min_age_days: int = 0):
|
|
76
79
|
return await self.robot_usecase.acquire_unhardened(limit, lock_minutes, min_age_days)
|
|
77
80
|
|
|
78
|
-
async def update_auth_status(self, robot_id: str, auth_status: str) -> None:
|
|
81
|
+
async def update_auth_status(self, robot_id: str, auth_status: str | RobotAuthStatus) -> None:
|
|
79
82
|
await self.robot_usecase.update_auth_status(robot_id, auth_status)
|
|
80
83
|
|
|
81
84
|
async def update_security_hardened(self, robot_id: str, security_hardened: bool) -> None:
|
|
82
85
|
await self.robot_usecase.update_security_hardened(robot_id, security_hardened)
|
|
83
86
|
|
|
84
|
-
|
|
87
|
+
async def update_metadata(self, robot_id: str, metadata: Dict[str, Any]) -> None:
|
|
88
|
+
await self.robot_usecase.update_metadata(robot_id, metadata)
|
|
89
|
+
|
|
90
|
+
__all__ = [
|
|
91
|
+
"RobotPlatformModule",
|
|
92
|
+
"AsyncRobotPlatformModule",
|
|
93
|
+
"Robot",
|
|
94
|
+
"RobotSecrets",
|
|
95
|
+
"RobotStatus",
|
|
96
|
+
"RobotAuthStatus",
|
|
97
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Optional, List, Tuple, Any, Dict
|
|
2
2
|
from ..domain.repositories import RobotRepository, AsyncRobotRepository
|
|
3
|
-
from ..domain.entities import Robot, RobotSecrets
|
|
3
|
+
from ..domain.entities import Robot, RobotSecrets, RobotStatus, RobotAuthStatus
|
|
4
4
|
|
|
5
5
|
class RobotUsecase:
|
|
6
6
|
def __init__(self, repo: RobotRepository):
|
|
@@ -15,7 +15,7 @@ class RobotUsecase:
|
|
|
15
15
|
def get_secrets(self, robot_id: str) -> Optional[RobotSecrets]:
|
|
16
16
|
return self.repo.get_secrets(robot_id)
|
|
17
17
|
|
|
18
|
-
def update_status(self, robot_id: str, status: str) -> None:
|
|
18
|
+
def update_status(self, robot_id: str, status: str | RobotStatus) -> None:
|
|
19
19
|
self.repo.update_status(robot_id, status)
|
|
20
20
|
|
|
21
21
|
def list_robots(self, platform: Optional[str] = None, status: Optional[str] = None, project_id: Optional[int] = None, page: int = 1, limit: int = 20) -> Dict[str, Any]:
|
|
@@ -33,12 +33,15 @@ class RobotUsecase:
|
|
|
33
33
|
def acquire_unhardened(self, limit: int = 20, lock_minutes: int = 30, min_age_days: int = 0) -> List[Robot]:
|
|
34
34
|
return self.repo.acquire_unhardened(limit, lock_minutes, min_age_days)
|
|
35
35
|
|
|
36
|
-
def update_auth_status(self, robot_id: str, auth_status: str) -> None:
|
|
36
|
+
def update_auth_status(self, robot_id: str, auth_status: str | RobotAuthStatus) -> None:
|
|
37
37
|
self.repo.update_auth_status(robot_id, auth_status)
|
|
38
38
|
|
|
39
39
|
def update_security_hardened(self, robot_id: str, security_hardened: bool) -> None:
|
|
40
40
|
self.repo.update_security_hardened(robot_id, security_hardened)
|
|
41
41
|
|
|
42
|
+
def update_metadata(self, robot_id: str, metadata: Dict[str, Any]) -> None:
|
|
43
|
+
self.repo.update_metadata(robot_id, metadata)
|
|
44
|
+
|
|
42
45
|
|
|
43
46
|
class AsyncRobotUsecase:
|
|
44
47
|
def __init__(self, repo: AsyncRobotRepository):
|
|
@@ -53,7 +56,7 @@ class AsyncRobotUsecase:
|
|
|
53
56
|
async def get_secrets(self, robot_id: str) -> Optional[RobotSecrets]:
|
|
54
57
|
return await self.repo.get_secrets(robot_id)
|
|
55
58
|
|
|
56
|
-
async def update_status(self, robot_id: str, status: str) -> None:
|
|
59
|
+
async def update_status(self, robot_id: str, status: str | RobotStatus) -> None:
|
|
57
60
|
await self.repo.update_status(robot_id, status)
|
|
58
61
|
|
|
59
62
|
async def list_robots(self, platform: Optional[str] = None, status: Optional[str] = None, project_id: Optional[int] = None, page: int = 1, limit: int = 20) -> Dict[str, Any]:
|
|
@@ -71,8 +74,11 @@ class AsyncRobotUsecase:
|
|
|
71
74
|
async def acquire_unhardened(self, limit: int = 20, lock_minutes: int = 30, min_age_days: int = 0) -> List[Robot]:
|
|
72
75
|
return await self.repo.acquire_unhardened(limit, lock_minutes, min_age_days)
|
|
73
76
|
|
|
74
|
-
async def update_auth_status(self, robot_id: str, auth_status: str) -> None:
|
|
77
|
+
async def update_auth_status(self, robot_id: str, auth_status: str | RobotAuthStatus) -> None:
|
|
75
78
|
await self.repo.update_auth_status(robot_id, auth_status)
|
|
76
79
|
|
|
77
80
|
async def update_security_hardened(self, robot_id: str, security_hardened: bool) -> None:
|
|
78
81
|
await self.repo.update_security_hardened(robot_id, security_hardened)
|
|
82
|
+
|
|
83
|
+
async def update_metadata(self, robot_id: str, metadata: Dict[str, Any]) -> None:
|
|
84
|
+
await self.repo.update_metadata(robot_id, metadata)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Optional, Any, Dict
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class RobotStatus(str, Enum):
|
|
7
|
+
LIVE = "live"
|
|
8
|
+
DEAD = "dead"
|
|
9
|
+
RUNNING = "running"
|
|
10
|
+
CHECKPOINT = "checkpoint"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class RobotAuthStatus(str, Enum):
|
|
14
|
+
AUTHORIZED = "authorized"
|
|
15
|
+
UNAUTHORIZED = "unauthorized"
|
|
16
|
+
LOGGED_OUT = "logged_out"
|
|
17
|
+
LOGIN_ERROR = "login_error"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def normalize_robot_status(status: str | RobotStatus) -> str:
|
|
21
|
+
if isinstance(status, RobotStatus):
|
|
22
|
+
return status.value
|
|
23
|
+
return str(status).strip().lower()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def normalize_robot_auth_status(status: str | RobotAuthStatus) -> str:
|
|
27
|
+
if isinstance(status, RobotAuthStatus):
|
|
28
|
+
return status.value
|
|
29
|
+
return str(status).strip().lower()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def ensure_valid_robot_status(status: str) -> None:
|
|
33
|
+
allowed = {s.value for s in RobotStatus}
|
|
34
|
+
if status not in allowed:
|
|
35
|
+
raise ValueError(f"invalid status: {status}. allowed={sorted(allowed)}")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def ensure_valid_robot_auth_status(status: str) -> None:
|
|
39
|
+
allowed = {s.value for s in RobotAuthStatus}
|
|
40
|
+
if status not in allowed:
|
|
41
|
+
raise ValueError(f"invalid auth_status: {status}. allowed={sorted(allowed)}")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def ensure_valid_worker_robot_auth_status(status: str) -> None:
|
|
45
|
+
ensure_valid_robot_auth_status(status)
|
|
46
|
+
if status == RobotAuthStatus.LOGIN_ERROR.value:
|
|
47
|
+
raise ValueError("auth_status login_error is not allowed for this endpoint")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def ensure_valid_worker_robot_status(status: str) -> None:
|
|
51
|
+
ensure_valid_robot_status(status)
|
|
52
|
+
if status == RobotStatus.CHECKPOINT.value:
|
|
53
|
+
raise ValueError("status checkpoint is not allowed for this endpoint")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def ensure_valid_metadata(metadata: Dict[str, Any]) -> None:
|
|
57
|
+
if not isinstance(metadata, dict):
|
|
58
|
+
raise ValueError("metadata must be a dict")
|
|
59
|
+
|
|
60
|
+
for key in metadata.keys():
|
|
61
|
+
if not isinstance(key, str):
|
|
62
|
+
raise ValueError("metadata keys must be strings")
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
import json
|
|
66
|
+
json.dumps(metadata)
|
|
67
|
+
except Exception as e:
|
|
68
|
+
raise ValueError(f"metadata must be JSON-serializable: {e}") from e
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class Robot:
|
|
73
|
+
id: str
|
|
74
|
+
username: str
|
|
75
|
+
platform: str
|
|
76
|
+
status: str
|
|
77
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
78
|
+
project_id: Optional[str] = None
|
|
79
|
+
primary_environment: Optional[str] = None
|
|
80
|
+
created_at: Optional[str] = None
|
|
81
|
+
|
|
82
|
+
@dataclass
|
|
83
|
+
class RobotSecrets:
|
|
84
|
+
password: str
|
|
85
|
+
two_fa_secret: str
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class RobotActivity:
|
|
89
|
+
id: str
|
|
90
|
+
activity_type: str
|
|
91
|
+
status: str
|
|
92
|
+
message: str
|
|
93
|
+
|
|
94
|
+
@dataclass
|
|
95
|
+
class AcquireNeedLoginRequest:
|
|
96
|
+
limit: int = 20
|
|
97
|
+
lock_minutes: int = 30
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class AcquireUnhardenedRequest:
|
|
101
|
+
limit: int = 20
|
|
102
|
+
lock_minutes: int = 30
|
|
103
|
+
min_age_days: int = 0
|
|
104
|
+
|
|
105
|
+
@dataclass
|
|
106
|
+
class UpdateAuthStatusRequest:
|
|
107
|
+
auth_status: str
|
|
108
|
+
|
|
109
|
+
@dataclass
|
|
110
|
+
class UpdateSecurityHardenedRequest:
|
|
111
|
+
security_hardened: bool
|
|
112
|
+
|
|
113
|
+
@dataclass
|
|
114
|
+
class StandardResponse:
|
|
115
|
+
status: str
|
|
116
|
+
code: int
|
|
117
|
+
message: str
|
|
118
|
+
data: Any = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from typing import Optional, List, Tuple
|
|
3
|
-
from .entities import Robot, RobotSecrets
|
|
3
|
+
from .entities import Robot, RobotSecrets, RobotStatus, RobotAuthStatus
|
|
4
4
|
|
|
5
5
|
class RobotRepository(ABC):
|
|
6
6
|
@abstractmethod
|
|
@@ -8,7 +8,7 @@ class RobotRepository(ABC):
|
|
|
8
8
|
pass
|
|
9
9
|
|
|
10
10
|
@abstractmethod
|
|
11
|
-
def update_status(self, robot_id: str, status: str) -> None:
|
|
11
|
+
def update_status(self, robot_id: str, status: str | RobotStatus) -> None:
|
|
12
12
|
pass
|
|
13
13
|
|
|
14
14
|
@abstractmethod
|
|
@@ -32,20 +32,24 @@ class RobotRepository(ABC):
|
|
|
32
32
|
pass
|
|
33
33
|
|
|
34
34
|
@abstractmethod
|
|
35
|
-
def update_auth_status(self, robot_id: str, auth_status: str) -> None:
|
|
35
|
+
def update_auth_status(self, robot_id: str, auth_status: str | RobotAuthStatus) -> None:
|
|
36
36
|
pass
|
|
37
37
|
|
|
38
38
|
@abstractmethod
|
|
39
39
|
def update_security_hardened(self, robot_id: str, security_hardened: bool) -> None:
|
|
40
40
|
pass
|
|
41
41
|
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def update_metadata(self, robot_id: str, metadata: dict) -> None:
|
|
44
|
+
pass
|
|
45
|
+
|
|
42
46
|
class AsyncRobotRepository(ABC):
|
|
43
47
|
@abstractmethod
|
|
44
48
|
async def find_by_id(self, robot_id: str) -> Optional[Robot]:
|
|
45
49
|
pass
|
|
46
50
|
|
|
47
51
|
@abstractmethod
|
|
48
|
-
async def update_status(self, robot_id: str, status: str) -> None:
|
|
52
|
+
async def update_status(self, robot_id: str, status: str | RobotStatus) -> None:
|
|
49
53
|
pass
|
|
50
54
|
|
|
51
55
|
@abstractmethod
|
|
@@ -69,9 +73,13 @@ class AsyncRobotRepository(ABC):
|
|
|
69
73
|
pass
|
|
70
74
|
|
|
71
75
|
@abstractmethod
|
|
72
|
-
async def update_auth_status(self, robot_id: str, auth_status: str) -> None:
|
|
76
|
+
async def update_auth_status(self, robot_id: str, auth_status: str | RobotAuthStatus) -> None:
|
|
73
77
|
pass
|
|
74
78
|
|
|
75
79
|
@abstractmethod
|
|
76
80
|
async def update_security_hardened(self, robot_id: str, security_hardened: bool) -> None:
|
|
77
81
|
pass
|
|
82
|
+
|
|
83
|
+
@abstractmethod
|
|
84
|
+
async def update_metadata(self, robot_id: str, metadata: dict) -> None:
|
|
85
|
+
pass
|
{robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_sdk/infrastructure/robot_api_repository.py
RENAMED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
from typing import Optional, List, Tuple, Dict, Any
|
|
2
2
|
from .api_client import HTTPClient, AsyncHTTPClient
|
|
3
3
|
from ..domain.repositories import RobotRepository, AsyncRobotRepository
|
|
4
|
-
from ..domain.entities import
|
|
4
|
+
from ..domain.entities import (
|
|
5
|
+
Robot,
|
|
6
|
+
RobotSecrets,
|
|
7
|
+
RobotStatus,
|
|
8
|
+
RobotAuthStatus,
|
|
9
|
+
normalize_robot_status,
|
|
10
|
+
normalize_robot_auth_status,
|
|
11
|
+
ensure_valid_worker_robot_status,
|
|
12
|
+
ensure_valid_worker_robot_auth_status,
|
|
13
|
+
)
|
|
5
14
|
|
|
6
15
|
|
|
7
16
|
def _extract_list_payload(resp: Dict[str, Any]) -> Tuple[List[Dict[str, Any]], int]:
|
|
@@ -38,8 +47,10 @@ class RobotAPIRepository(RobotRepository):
|
|
|
38
47
|
resp = self.client.request("GET", f"/robots/{robot_id}")
|
|
39
48
|
return Robot(**resp) if resp else None
|
|
40
49
|
|
|
41
|
-
def update_status(self, robot_id: str, status: str) -> None:
|
|
42
|
-
|
|
50
|
+
def update_status(self, robot_id: str, status: str | RobotStatus) -> None:
|
|
51
|
+
normalized_status = normalize_robot_status(status)
|
|
52
|
+
ensure_valid_worker_robot_status(normalized_status)
|
|
53
|
+
self.client.request("PATCH", f"/robots/{robot_id}/status", json={"status": normalized_status})
|
|
43
54
|
|
|
44
55
|
def delete_robot(self, robot_id: str) -> None:
|
|
45
56
|
self.client.request("DELETE", f"/robots/{robot_id}")
|
|
@@ -76,11 +87,13 @@ class RobotAPIRepository(RobotRepository):
|
|
|
76
87
|
data = _extract_items(resp)
|
|
77
88
|
return [Robot(**r) for r in data]
|
|
78
89
|
|
|
79
|
-
def update_auth_status(self, robot_id: str, auth_status: str) -> None:
|
|
90
|
+
def update_auth_status(self, robot_id: str, auth_status: str | RobotAuthStatus) -> None:
|
|
91
|
+
normalized_auth_status = normalize_robot_auth_status(auth_status)
|
|
92
|
+
ensure_valid_worker_robot_auth_status(normalized_auth_status)
|
|
80
93
|
self.client.request(
|
|
81
94
|
"PATCH",
|
|
82
95
|
f"/robots/{robot_id}/auth-status",
|
|
83
|
-
json={"auth_status":
|
|
96
|
+
json={"auth_status": normalized_auth_status},
|
|
84
97
|
)
|
|
85
98
|
|
|
86
99
|
def update_security_hardened(self, robot_id: str, security_hardened: bool) -> None:
|
|
@@ -90,6 +103,13 @@ class RobotAPIRepository(RobotRepository):
|
|
|
90
103
|
json={"security_hardened": security_hardened},
|
|
91
104
|
)
|
|
92
105
|
|
|
106
|
+
def update_metadata(self, robot_id: str, metadata: Dict[str, Any]) -> None:
|
|
107
|
+
self.client.request(
|
|
108
|
+
"PATCH",
|
|
109
|
+
f"/robots/{robot_id}",
|
|
110
|
+
json={"metadata": metadata},
|
|
111
|
+
)
|
|
112
|
+
|
|
93
113
|
class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
94
114
|
def __init__(self, client: AsyncHTTPClient):
|
|
95
115
|
self.client = client
|
|
@@ -98,8 +118,10 @@ class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
|
98
118
|
resp = await self.client.request("GET", f"/robots/{robot_id}")
|
|
99
119
|
return Robot(**resp) if resp else None
|
|
100
120
|
|
|
101
|
-
async def update_status(self, robot_id: str, status: str) -> None:
|
|
102
|
-
|
|
121
|
+
async def update_status(self, robot_id: str, status: str | RobotStatus) -> None:
|
|
122
|
+
normalized_status = normalize_robot_status(status)
|
|
123
|
+
ensure_valid_worker_robot_status(normalized_status)
|
|
124
|
+
await self.client.request("PATCH", f"/robots/{robot_id}/status", json={"status": normalized_status})
|
|
103
125
|
|
|
104
126
|
async def delete_robot(self, robot_id: str) -> None:
|
|
105
127
|
await self.client.request("DELETE", f"/robots/{robot_id}")
|
|
@@ -136,11 +158,13 @@ class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
|
136
158
|
data = _extract_items(resp)
|
|
137
159
|
return [Robot(**r) for r in data]
|
|
138
160
|
|
|
139
|
-
async def update_auth_status(self, robot_id: str, auth_status: str) -> None:
|
|
161
|
+
async def update_auth_status(self, robot_id: str, auth_status: str | RobotAuthStatus) -> None:
|
|
162
|
+
normalized_auth_status = normalize_robot_auth_status(auth_status)
|
|
163
|
+
ensure_valid_worker_robot_auth_status(normalized_auth_status)
|
|
140
164
|
await self.client.request(
|
|
141
165
|
"PATCH",
|
|
142
166
|
f"/robots/{robot_id}/auth-status",
|
|
143
|
-
json={"auth_status":
|
|
167
|
+
json={"auth_status": normalized_auth_status},
|
|
144
168
|
)
|
|
145
169
|
|
|
146
170
|
async def update_security_hardened(self, robot_id: str, security_hardened: bool) -> None:
|
|
@@ -149,3 +173,10 @@ class AsyncRobotAPIRepository(AsyncRobotRepository):
|
|
|
149
173
|
f"/robots/{robot_id}/security-hardened",
|
|
150
174
|
json={"security_hardened": security_hardened},
|
|
151
175
|
)
|
|
176
|
+
|
|
177
|
+
async def update_metadata(self, robot_id: str, metadata: Dict[str, Any]) -> None:
|
|
178
|
+
await self.client.request(
|
|
179
|
+
"PATCH",
|
|
180
|
+
f"/robots/{robot_id}",
|
|
181
|
+
json={"metadata": metadata},
|
|
182
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: robot-wrapper-sdk
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: Robot Platform API SDK
|
|
5
5
|
Author-email: GH Robot Platform Team <team@ghrobot.com>
|
|
6
6
|
License: MIT
|
|
@@ -38,7 +38,7 @@ Or pass values directly when creating the module.
|
|
|
38
38
|
## Quick Start (Sync)
|
|
39
39
|
|
|
40
40
|
```python
|
|
41
|
-
from robot_sdk import RobotPlatformModule
|
|
41
|
+
from robot_sdk import RobotPlatformModule, RobotStatus, RobotAuthStatus
|
|
42
42
|
|
|
43
43
|
sdk = RobotPlatformModule(
|
|
44
44
|
base_url="http://localhost:8085",
|
|
@@ -51,14 +51,14 @@ sdk = RobotPlatformModule(
|
|
|
51
51
|
robot = sdk.get_robot("2047631542552334336")
|
|
52
52
|
print(robot.platform if robot else "not found")
|
|
53
53
|
|
|
54
|
-
# Update lifecycle status
|
|
55
|
-
sdk.update_status("2047631542552334336",
|
|
54
|
+
# Update lifecycle status (prefer enum)
|
|
55
|
+
sdk.update_status("2047631542552334336", RobotStatus.LIVE)
|
|
56
56
|
|
|
57
57
|
# Acquire login tasks
|
|
58
58
|
login_tasks = sdk.acquire_need_login(limit=20, lock_minutes=30)
|
|
59
59
|
|
|
60
|
-
# Update auth status after worker result
|
|
61
|
-
sdk.update_auth_status("2047631542552334336",
|
|
60
|
+
# Update auth status after worker result (prefer enum)
|
|
61
|
+
sdk.update_auth_status("2047631542552334336", RobotAuthStatus.AUTHORIZED)
|
|
62
62
|
# allowed values: authorized | unauthorized | logged_out
|
|
63
63
|
|
|
64
64
|
# Acquire hardening tasks
|
|
@@ -67,6 +67,12 @@ hardening_tasks = sdk.acquire_unhardened(limit=20, lock_minutes=30, min_age_days
|
|
|
67
67
|
# Update hardening status after worker result
|
|
68
68
|
sdk.update_security_hardened("2047631542552334336", True)
|
|
69
69
|
|
|
70
|
+
# Update metadata (partial patch)
|
|
71
|
+
sdk.update_metadata("2047631542552334336", {
|
|
72
|
+
"country_code": "VN",
|
|
73
|
+
"note": "updated by sdk"
|
|
74
|
+
})
|
|
75
|
+
|
|
70
76
|
sdk.close()
|
|
71
77
|
```
|
|
72
78
|
|
|
@@ -74,7 +80,7 @@ sdk.close()
|
|
|
74
80
|
|
|
75
81
|
```python
|
|
76
82
|
import asyncio
|
|
77
|
-
from robot_sdk import AsyncRobotPlatformModule
|
|
83
|
+
from robot_sdk import AsyncRobotPlatformModule, RobotAuthStatus
|
|
78
84
|
|
|
79
85
|
async def main():
|
|
80
86
|
sdk = AsyncRobotPlatformModule(
|
|
@@ -86,8 +92,12 @@ async def main():
|
|
|
86
92
|
robot = await sdk.get_robot("2047631542552334336")
|
|
87
93
|
print(robot.platform if robot else "not found")
|
|
88
94
|
|
|
89
|
-
await sdk.update_auth_status("2047631542552334336",
|
|
95
|
+
await sdk.update_auth_status("2047631542552334336", RobotAuthStatus.AUTHORIZED)
|
|
90
96
|
await sdk.update_security_hardened("2047631542552334336", True)
|
|
97
|
+
await sdk.update_metadata("2047631542552334336", {
|
|
98
|
+
"country_code": "VN",
|
|
99
|
+
"note": "updated by async sdk"
|
|
100
|
+
})
|
|
91
101
|
|
|
92
102
|
await sdk.close()
|
|
93
103
|
|
|
@@ -145,6 +155,7 @@ Update endpoints return:
|
|
|
145
155
|
- `acquire_unhardened(limit=20, lock_minutes=30, min_age_days=0)`
|
|
146
156
|
- `update_auth_status(robot_id, auth_status)`
|
|
147
157
|
- `update_security_hardened(robot_id, security_hardened)`
|
|
158
|
+
- `update_metadata(robot_id, metadata)`
|
|
148
159
|
- `close()`
|
|
149
160
|
|
|
150
161
|
### `AsyncRobotPlatformModule` (async)
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass, field
|
|
2
|
-
from typing import Optional, Any, Dict
|
|
3
|
-
|
|
4
|
-
@dataclass
|
|
5
|
-
class Robot:
|
|
6
|
-
id: str
|
|
7
|
-
username: str
|
|
8
|
-
platform: str
|
|
9
|
-
status: str
|
|
10
|
-
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
11
|
-
project_id: Optional[str] = None
|
|
12
|
-
primary_environment: Optional[str] = None
|
|
13
|
-
created_at: Optional[str] = None
|
|
14
|
-
|
|
15
|
-
@dataclass
|
|
16
|
-
class RobotSecrets:
|
|
17
|
-
password: str
|
|
18
|
-
two_fa_secret: str
|
|
19
|
-
|
|
20
|
-
@dataclass
|
|
21
|
-
class RobotActivity:
|
|
22
|
-
id: str
|
|
23
|
-
activity_type: str
|
|
24
|
-
status: str
|
|
25
|
-
message: str
|
|
26
|
-
|
|
27
|
-
@dataclass
|
|
28
|
-
class AcquireNeedLoginRequest:
|
|
29
|
-
limit: int = 20
|
|
30
|
-
lock_minutes: int = 30
|
|
31
|
-
|
|
32
|
-
@dataclass
|
|
33
|
-
class AcquireUnhardenedRequest:
|
|
34
|
-
limit: int = 20
|
|
35
|
-
lock_minutes: int = 30
|
|
36
|
-
min_age_days: int = 0
|
|
37
|
-
|
|
38
|
-
@dataclass
|
|
39
|
-
class UpdateAuthStatusRequest:
|
|
40
|
-
auth_status: str
|
|
41
|
-
|
|
42
|
-
@dataclass
|
|
43
|
-
class UpdateSecurityHardenedRequest:
|
|
44
|
-
security_hardened: bool
|
|
45
|
-
|
|
46
|
-
@dataclass
|
|
47
|
-
class StandardResponse:
|
|
48
|
-
status: str
|
|
49
|
-
code: int
|
|
50
|
-
message: str
|
|
51
|
-
data: Any = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_wrapper_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{robot_wrapper_sdk-0.2.7 → robot_wrapper_sdk-0.2.8}/robot_wrapper_sdk.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|