magic-campus-sdk 0.1.0__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.
- magic_campus_sdk-0.1.0/PKG-INFO +165 -0
- magic_campus_sdk-0.1.0/README.md +151 -0
- magic_campus_sdk-0.1.0/magic_campus_sdk.egg-info/PKG-INFO +165 -0
- magic_campus_sdk-0.1.0/magic_campus_sdk.egg-info/SOURCES.txt +63 -0
- magic_campus_sdk-0.1.0/magic_campus_sdk.egg-info/dependency_links.txt +1 -0
- magic_campus_sdk-0.1.0/magic_campus_sdk.egg-info/entry_points.txt +2 -0
- magic_campus_sdk-0.1.0/magic_campus_sdk.egg-info/requires.txt +6 -0
- magic_campus_sdk-0.1.0/magic_campus_sdk.egg-info/top_level.txt +2 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/__init__.py +1 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/__main__.py +9 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/accounts.py +126 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/cli.py +118 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/client.py +99 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/commands/auth.py +26 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/commands/config.py +95 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/commands/feed.py +23 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/commands/im.py +20 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/commands/notify.py +92 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/commands/user.py +66 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/config_store.py +57 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/http_send.py +565 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/notify.py +357 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/output.py +101 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/prompts.py +58 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/targets.py +26 -0
- magic_campus_sdk-0.1.0/magiccampus_cli/utils.py +67 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/__init__.py +118 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/auth.py +111 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/client.py +89 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/example.py +46 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/example_ws.py +59 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/feed_client.py +21 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/__init__.py +85 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/client.py +913 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/gob_codec.py +289 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/http_api.py +58 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/media.py +761 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/models.py +583 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/proto/__init__.py +21 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/proto/sdkws/__init__.py +1 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/proto/sdkws/sdkws_pb2.py +215 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/proto/wrapperspb/__init__.py +1 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/proto/wrapperspb/wrapperspb_pb2.py +45 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/self_user_info_api.py +48 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/storage.py +213 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/text.py +49 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/im/ws_client.py +1235 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/models.py +164 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/platform_client.py +119 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/platform_http.py +71 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/platform_ws.py +122 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/user_client.py +36 -0
- magic_campus_sdk-0.1.0/magiccampus_sdk/user_info_api.py +55 -0
- magic_campus_sdk-0.1.0/pyproject.toml +37 -0
- magic_campus_sdk-0.1.0/setup.cfg +4 -0
- magic_campus_sdk-0.1.0/tests/test_auth.py +64 -0
- magic_campus_sdk-0.1.0/tests/test_auth_status.py +57 -0
- magic_campus_sdk-0.1.0/tests/test_cli_config.py +39 -0
- magic_campus_sdk-0.1.0/tests/test_cli_domains.py +204 -0
- magic_campus_sdk-0.1.0/tests/test_cli_interactive.py +34 -0
- magic_campus_sdk-0.1.0/tests/test_cli_main.py +23 -0
- magic_campus_sdk-0.1.0/tests/test_cli_notify.py +294 -0
- magic_campus_sdk-0.1.0/tests/test_im_namespace.py +18 -0
- magic_campus_sdk-0.1.0/tests/test_smoke_cli.py +53 -0
- magic_campus_sdk-0.1.0/tests/test_ws_client.py +73 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: magic-campus-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MagicCampus platform SDK and CLI with bundled IM transport support.
|
|
5
|
+
Author: MagicCampus Contributors
|
|
6
|
+
License-Expression: AGPL-3.0-or-later
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: httpx<1,>=0.27
|
|
10
|
+
Requires-Dist: protobuf<7,>=6.32.0
|
|
11
|
+
Requires-Dist: websocket-client<2,>=1.8.0
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
14
|
+
|
|
15
|
+
# magic-campus-sdk
|
|
16
|
+
|
|
17
|
+
Python SDK and CLI for MagicCampus platform integrations. IM remains a supported domain, and this repository keeps the bundled OpenIM transport inside `magiccampus_sdk`.
|
|
18
|
+
|
|
19
|
+
This project removes direct user-facing dependency on OpenIM token and endpoint configuration. You only configure:
|
|
20
|
+
|
|
21
|
+
- `apiurl`
|
|
22
|
+
- `apikey`
|
|
23
|
+
- `platform`
|
|
24
|
+
|
|
25
|
+
At runtime, IM-backed flows call:
|
|
26
|
+
|
|
27
|
+
`GET /api/v1/accounts/imToken?platform=<PLATFORM>`
|
|
28
|
+
|
|
29
|
+
and uses the response fields:
|
|
30
|
+
|
|
31
|
+
- `userId`
|
|
32
|
+
- `imToken`
|
|
33
|
+
- `wsApi`
|
|
34
|
+
- `httpApi`
|
|
35
|
+
|
|
36
|
+
## Install locally
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
uv sync
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This repository vendors only the OpenIM transport pieces that `magiccampus_sdk` actually uses, and layers platform-facing SDK / CLI commands on top.
|
|
43
|
+
|
|
44
|
+
IM-specific low-level internals, models, and protobufs now live under `magiccampus_sdk.im`.
|
|
45
|
+
|
|
46
|
+
## CLI quick start
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
magic-campus --help
|
|
50
|
+
magic-campus config init --apiurl https://api-test.pearlapi.com --apikey "$MAGICCAMPUS_APIKEY" --platform IOS --default true
|
|
51
|
+
magic-campus auth status --format pretty
|
|
52
|
+
magic-campus im notify send --to user:10134002 --text "hello"
|
|
53
|
+
magic-campus user get --id 10134002 --format pretty
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`magic-campus config init` also supports an interactive TTY flow when you omit auth flags.
|
|
57
|
+
|
|
58
|
+
`im notify send` sends over MagicCampus HTTP `POST /agent/v1/im/sendMessage`. `im notify history` still relies on the websocket transport and local sync database.
|
|
59
|
+
|
|
60
|
+
Legacy compatibility commands remain available:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
magic-campus notify +send --to user:10134002 --text "hello"
|
|
64
|
+
magic-campus notify +history --to user:10134002
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
CLI config is stored at:
|
|
68
|
+
|
|
69
|
+
`~/.mushroom_agent/auth/magiccampus-im-sdk.json`
|
|
70
|
+
|
|
71
|
+
Supported commands:
|
|
72
|
+
|
|
73
|
+
- `config init|list|use|remove`
|
|
74
|
+
- `auth status`
|
|
75
|
+
- `im notify send`
|
|
76
|
+
- `im notify history`
|
|
77
|
+
- `user get`
|
|
78
|
+
- `feed list`
|
|
79
|
+
- `notify +send` (compat)
|
|
80
|
+
- `notify +history` (compat)
|
|
81
|
+
|
|
82
|
+
## Python SDK quick start
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from magiccampus_sdk import MagicCampusClient, MagicCampusClientConfig
|
|
86
|
+
|
|
87
|
+
client = MagicCampusClient(
|
|
88
|
+
MagicCampusClientConfig(
|
|
89
|
+
apiurl="https://api-test.pearlapi.com",
|
|
90
|
+
apikey="YOUR_API_KEY",
|
|
91
|
+
platform="IOS",
|
|
92
|
+
data_dir="./magiccampus_data",
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
user = client.user.get("10134002")
|
|
97
|
+
print(user.nickname)
|
|
98
|
+
print(user.avatar_url)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Python websocket quick start
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from magiccampus_sdk import MagicCampusWSSDK, MagicCampusWSConfig
|
|
105
|
+
|
|
106
|
+
sdk = MagicCampusWSSDK(
|
|
107
|
+
MagicCampusWSConfig(
|
|
108
|
+
apiurl="https://api-test.pearlapi.com",
|
|
109
|
+
apikey="YOUR_API_KEY",
|
|
110
|
+
platform="IOS",
|
|
111
|
+
data_dir="./magiccampus_data",
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
sdk.login()
|
|
116
|
+
sdk.start()
|
|
117
|
+
sdk.send_text("hello", recv_id="10134002")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Runnable examples live in [magiccampus_sdk/example.py](magiccampus_sdk/example.py) and [magiccampus_sdk/example_ws.py](magiccampus_sdk/example_ws.py).
|
|
121
|
+
|
|
122
|
+
## CLI smoke script
|
|
123
|
+
|
|
124
|
+
An executable smoke helper lives at [scripts/smoke_cli.py](scripts/smoke_cli.py).
|
|
125
|
+
|
|
126
|
+
Offline-safe mode only exercises config persistence and notify dry-run:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
uv run python scripts/smoke_cli.py
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
This mode does not require a real API key. It uses a placeholder key by default and avoids any live auth call.
|
|
133
|
+
|
|
134
|
+
## Real network mode
|
|
135
|
+
|
|
136
|
+
To run the live auth probe, provide a real API key and enable `--live`:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
export MAGICCAMPUS_APIURL=https://api-test.pearlapi.com
|
|
140
|
+
export MAGICCAMPUS_APIKEY='your real api key'
|
|
141
|
+
export MAGICCAMPUS_PLATFORM=IOS
|
|
142
|
+
uv run python scripts/smoke_cli.py --live
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Optional variables:
|
|
146
|
+
|
|
147
|
+
- `MAGICCAMPUS_SMOKE_TARGET`: target used by dry-run and optional live send, default `user:smoke-target`
|
|
148
|
+
- `MAGICCAMPUS_PLATFORM`: defaults to `IOS`
|
|
149
|
+
|
|
150
|
+
If you also want to send a real text message, set a real target and pass `--live-send`:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
export MAGICCAMPUS_SMOKE_TARGET='user:10134002'
|
|
154
|
+
uv run python scripts/smoke_cli.py --live --live-send --text 'hello from smoke script'
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`--live-send` performs a real outbound send, so use it only with a valid target and credentials.
|
|
158
|
+
|
|
159
|
+
## Notes
|
|
160
|
+
|
|
161
|
+
- `apiurl` can point to any MagicCampus API base URL; IM-backed flows append `/api/v1/accounts/imToken`
|
|
162
|
+
- `client.user.get(...)` calls `GET /api/v1/accounts/getUserInfo` with `apiurl` and `apikey` directly
|
|
163
|
+
- `platform` defaults to `IOS`
|
|
164
|
+
- low-level IM send / receive behavior comes from the bundled transport modules inside `magiccampus_sdk`
|
|
165
|
+
- the wrapper does not persist raw OpenIM credentials in CLI config
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# magic-campus-sdk
|
|
2
|
+
|
|
3
|
+
Python SDK and CLI for MagicCampus platform integrations. IM remains a supported domain, and this repository keeps the bundled OpenIM transport inside `magiccampus_sdk`.
|
|
4
|
+
|
|
5
|
+
This project removes direct user-facing dependency on OpenIM token and endpoint configuration. You only configure:
|
|
6
|
+
|
|
7
|
+
- `apiurl`
|
|
8
|
+
- `apikey`
|
|
9
|
+
- `platform`
|
|
10
|
+
|
|
11
|
+
At runtime, IM-backed flows call:
|
|
12
|
+
|
|
13
|
+
`GET /api/v1/accounts/imToken?platform=<PLATFORM>`
|
|
14
|
+
|
|
15
|
+
and uses the response fields:
|
|
16
|
+
|
|
17
|
+
- `userId`
|
|
18
|
+
- `imToken`
|
|
19
|
+
- `wsApi`
|
|
20
|
+
- `httpApi`
|
|
21
|
+
|
|
22
|
+
## Install locally
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
uv sync
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This repository vendors only the OpenIM transport pieces that `magiccampus_sdk` actually uses, and layers platform-facing SDK / CLI commands on top.
|
|
29
|
+
|
|
30
|
+
IM-specific low-level internals, models, and protobufs now live under `magiccampus_sdk.im`.
|
|
31
|
+
|
|
32
|
+
## CLI quick start
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
magic-campus --help
|
|
36
|
+
magic-campus config init --apiurl https://api-test.pearlapi.com --apikey "$MAGICCAMPUS_APIKEY" --platform IOS --default true
|
|
37
|
+
magic-campus auth status --format pretty
|
|
38
|
+
magic-campus im notify send --to user:10134002 --text "hello"
|
|
39
|
+
magic-campus user get --id 10134002 --format pretty
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`magic-campus config init` also supports an interactive TTY flow when you omit auth flags.
|
|
43
|
+
|
|
44
|
+
`im notify send` sends over MagicCampus HTTP `POST /agent/v1/im/sendMessage`. `im notify history` still relies on the websocket transport and local sync database.
|
|
45
|
+
|
|
46
|
+
Legacy compatibility commands remain available:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
magic-campus notify +send --to user:10134002 --text "hello"
|
|
50
|
+
magic-campus notify +history --to user:10134002
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
CLI config is stored at:
|
|
54
|
+
|
|
55
|
+
`~/.mushroom_agent/auth/magiccampus-im-sdk.json`
|
|
56
|
+
|
|
57
|
+
Supported commands:
|
|
58
|
+
|
|
59
|
+
- `config init|list|use|remove`
|
|
60
|
+
- `auth status`
|
|
61
|
+
- `im notify send`
|
|
62
|
+
- `im notify history`
|
|
63
|
+
- `user get`
|
|
64
|
+
- `feed list`
|
|
65
|
+
- `notify +send` (compat)
|
|
66
|
+
- `notify +history` (compat)
|
|
67
|
+
|
|
68
|
+
## Python SDK quick start
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from magiccampus_sdk import MagicCampusClient, MagicCampusClientConfig
|
|
72
|
+
|
|
73
|
+
client = MagicCampusClient(
|
|
74
|
+
MagicCampusClientConfig(
|
|
75
|
+
apiurl="https://api-test.pearlapi.com",
|
|
76
|
+
apikey="YOUR_API_KEY",
|
|
77
|
+
platform="IOS",
|
|
78
|
+
data_dir="./magiccampus_data",
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
user = client.user.get("10134002")
|
|
83
|
+
print(user.nickname)
|
|
84
|
+
print(user.avatar_url)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Python websocket quick start
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from magiccampus_sdk import MagicCampusWSSDK, MagicCampusWSConfig
|
|
91
|
+
|
|
92
|
+
sdk = MagicCampusWSSDK(
|
|
93
|
+
MagicCampusWSConfig(
|
|
94
|
+
apiurl="https://api-test.pearlapi.com",
|
|
95
|
+
apikey="YOUR_API_KEY",
|
|
96
|
+
platform="IOS",
|
|
97
|
+
data_dir="./magiccampus_data",
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
sdk.login()
|
|
102
|
+
sdk.start()
|
|
103
|
+
sdk.send_text("hello", recv_id="10134002")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Runnable examples live in [magiccampus_sdk/example.py](magiccampus_sdk/example.py) and [magiccampus_sdk/example_ws.py](magiccampus_sdk/example_ws.py).
|
|
107
|
+
|
|
108
|
+
## CLI smoke script
|
|
109
|
+
|
|
110
|
+
An executable smoke helper lives at [scripts/smoke_cli.py](scripts/smoke_cli.py).
|
|
111
|
+
|
|
112
|
+
Offline-safe mode only exercises config persistence and notify dry-run:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
uv run python scripts/smoke_cli.py
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This mode does not require a real API key. It uses a placeholder key by default and avoids any live auth call.
|
|
119
|
+
|
|
120
|
+
## Real network mode
|
|
121
|
+
|
|
122
|
+
To run the live auth probe, provide a real API key and enable `--live`:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
export MAGICCAMPUS_APIURL=https://api-test.pearlapi.com
|
|
126
|
+
export MAGICCAMPUS_APIKEY='your real api key'
|
|
127
|
+
export MAGICCAMPUS_PLATFORM=IOS
|
|
128
|
+
uv run python scripts/smoke_cli.py --live
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Optional variables:
|
|
132
|
+
|
|
133
|
+
- `MAGICCAMPUS_SMOKE_TARGET`: target used by dry-run and optional live send, default `user:smoke-target`
|
|
134
|
+
- `MAGICCAMPUS_PLATFORM`: defaults to `IOS`
|
|
135
|
+
|
|
136
|
+
If you also want to send a real text message, set a real target and pass `--live-send`:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
export MAGICCAMPUS_SMOKE_TARGET='user:10134002'
|
|
140
|
+
uv run python scripts/smoke_cli.py --live --live-send --text 'hello from smoke script'
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`--live-send` performs a real outbound send, so use it only with a valid target and credentials.
|
|
144
|
+
|
|
145
|
+
## Notes
|
|
146
|
+
|
|
147
|
+
- `apiurl` can point to any MagicCampus API base URL; IM-backed flows append `/api/v1/accounts/imToken`
|
|
148
|
+
- `client.user.get(...)` calls `GET /api/v1/accounts/getUserInfo` with `apiurl` and `apikey` directly
|
|
149
|
+
- `platform` defaults to `IOS`
|
|
150
|
+
- low-level IM send / receive behavior comes from the bundled transport modules inside `magiccampus_sdk`
|
|
151
|
+
- the wrapper does not persist raw OpenIM credentials in CLI config
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: magic-campus-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MagicCampus platform SDK and CLI with bundled IM transport support.
|
|
5
|
+
Author: MagicCampus Contributors
|
|
6
|
+
License-Expression: AGPL-3.0-or-later
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: httpx<1,>=0.27
|
|
10
|
+
Requires-Dist: protobuf<7,>=6.32.0
|
|
11
|
+
Requires-Dist: websocket-client<2,>=1.8.0
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
14
|
+
|
|
15
|
+
# magic-campus-sdk
|
|
16
|
+
|
|
17
|
+
Python SDK and CLI for MagicCampus platform integrations. IM remains a supported domain, and this repository keeps the bundled OpenIM transport inside `magiccampus_sdk`.
|
|
18
|
+
|
|
19
|
+
This project removes direct user-facing dependency on OpenIM token and endpoint configuration. You only configure:
|
|
20
|
+
|
|
21
|
+
- `apiurl`
|
|
22
|
+
- `apikey`
|
|
23
|
+
- `platform`
|
|
24
|
+
|
|
25
|
+
At runtime, IM-backed flows call:
|
|
26
|
+
|
|
27
|
+
`GET /api/v1/accounts/imToken?platform=<PLATFORM>`
|
|
28
|
+
|
|
29
|
+
and uses the response fields:
|
|
30
|
+
|
|
31
|
+
- `userId`
|
|
32
|
+
- `imToken`
|
|
33
|
+
- `wsApi`
|
|
34
|
+
- `httpApi`
|
|
35
|
+
|
|
36
|
+
## Install locally
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
uv sync
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This repository vendors only the OpenIM transport pieces that `magiccampus_sdk` actually uses, and layers platform-facing SDK / CLI commands on top.
|
|
43
|
+
|
|
44
|
+
IM-specific low-level internals, models, and protobufs now live under `magiccampus_sdk.im`.
|
|
45
|
+
|
|
46
|
+
## CLI quick start
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
magic-campus --help
|
|
50
|
+
magic-campus config init --apiurl https://api-test.pearlapi.com --apikey "$MAGICCAMPUS_APIKEY" --platform IOS --default true
|
|
51
|
+
magic-campus auth status --format pretty
|
|
52
|
+
magic-campus im notify send --to user:10134002 --text "hello"
|
|
53
|
+
magic-campus user get --id 10134002 --format pretty
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`magic-campus config init` also supports an interactive TTY flow when you omit auth flags.
|
|
57
|
+
|
|
58
|
+
`im notify send` sends over MagicCampus HTTP `POST /agent/v1/im/sendMessage`. `im notify history` still relies on the websocket transport and local sync database.
|
|
59
|
+
|
|
60
|
+
Legacy compatibility commands remain available:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
magic-campus notify +send --to user:10134002 --text "hello"
|
|
64
|
+
magic-campus notify +history --to user:10134002
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
CLI config is stored at:
|
|
68
|
+
|
|
69
|
+
`~/.mushroom_agent/auth/magiccampus-im-sdk.json`
|
|
70
|
+
|
|
71
|
+
Supported commands:
|
|
72
|
+
|
|
73
|
+
- `config init|list|use|remove`
|
|
74
|
+
- `auth status`
|
|
75
|
+
- `im notify send`
|
|
76
|
+
- `im notify history`
|
|
77
|
+
- `user get`
|
|
78
|
+
- `feed list`
|
|
79
|
+
- `notify +send` (compat)
|
|
80
|
+
- `notify +history` (compat)
|
|
81
|
+
|
|
82
|
+
## Python SDK quick start
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from magiccampus_sdk import MagicCampusClient, MagicCampusClientConfig
|
|
86
|
+
|
|
87
|
+
client = MagicCampusClient(
|
|
88
|
+
MagicCampusClientConfig(
|
|
89
|
+
apiurl="https://api-test.pearlapi.com",
|
|
90
|
+
apikey="YOUR_API_KEY",
|
|
91
|
+
platform="IOS",
|
|
92
|
+
data_dir="./magiccampus_data",
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
user = client.user.get("10134002")
|
|
97
|
+
print(user.nickname)
|
|
98
|
+
print(user.avatar_url)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Python websocket quick start
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from magiccampus_sdk import MagicCampusWSSDK, MagicCampusWSConfig
|
|
105
|
+
|
|
106
|
+
sdk = MagicCampusWSSDK(
|
|
107
|
+
MagicCampusWSConfig(
|
|
108
|
+
apiurl="https://api-test.pearlapi.com",
|
|
109
|
+
apikey="YOUR_API_KEY",
|
|
110
|
+
platform="IOS",
|
|
111
|
+
data_dir="./magiccampus_data",
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
sdk.login()
|
|
116
|
+
sdk.start()
|
|
117
|
+
sdk.send_text("hello", recv_id="10134002")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Runnable examples live in [magiccampus_sdk/example.py](magiccampus_sdk/example.py) and [magiccampus_sdk/example_ws.py](magiccampus_sdk/example_ws.py).
|
|
121
|
+
|
|
122
|
+
## CLI smoke script
|
|
123
|
+
|
|
124
|
+
An executable smoke helper lives at [scripts/smoke_cli.py](scripts/smoke_cli.py).
|
|
125
|
+
|
|
126
|
+
Offline-safe mode only exercises config persistence and notify dry-run:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
uv run python scripts/smoke_cli.py
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
This mode does not require a real API key. It uses a placeholder key by default and avoids any live auth call.
|
|
133
|
+
|
|
134
|
+
## Real network mode
|
|
135
|
+
|
|
136
|
+
To run the live auth probe, provide a real API key and enable `--live`:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
export MAGICCAMPUS_APIURL=https://api-test.pearlapi.com
|
|
140
|
+
export MAGICCAMPUS_APIKEY='your real api key'
|
|
141
|
+
export MAGICCAMPUS_PLATFORM=IOS
|
|
142
|
+
uv run python scripts/smoke_cli.py --live
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Optional variables:
|
|
146
|
+
|
|
147
|
+
- `MAGICCAMPUS_SMOKE_TARGET`: target used by dry-run and optional live send, default `user:smoke-target`
|
|
148
|
+
- `MAGICCAMPUS_PLATFORM`: defaults to `IOS`
|
|
149
|
+
|
|
150
|
+
If you also want to send a real text message, set a real target and pass `--live-send`:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
export MAGICCAMPUS_SMOKE_TARGET='user:10134002'
|
|
154
|
+
uv run python scripts/smoke_cli.py --live --live-send --text 'hello from smoke script'
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`--live-send` performs a real outbound send, so use it only with a valid target and credentials.
|
|
158
|
+
|
|
159
|
+
## Notes
|
|
160
|
+
|
|
161
|
+
- `apiurl` can point to any MagicCampus API base URL; IM-backed flows append `/api/v1/accounts/imToken`
|
|
162
|
+
- `client.user.get(...)` calls `GET /api/v1/accounts/getUserInfo` with `apiurl` and `apikey` directly
|
|
163
|
+
- `platform` defaults to `IOS`
|
|
164
|
+
- low-level IM send / receive behavior comes from the bundled transport modules inside `magiccampus_sdk`
|
|
165
|
+
- the wrapper does not persist raw OpenIM credentials in CLI config
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
magic_campus_sdk.egg-info/PKG-INFO
|
|
4
|
+
magic_campus_sdk.egg-info/SOURCES.txt
|
|
5
|
+
magic_campus_sdk.egg-info/dependency_links.txt
|
|
6
|
+
magic_campus_sdk.egg-info/entry_points.txt
|
|
7
|
+
magic_campus_sdk.egg-info/requires.txt
|
|
8
|
+
magic_campus_sdk.egg-info/top_level.txt
|
|
9
|
+
magiccampus_cli/__init__.py
|
|
10
|
+
magiccampus_cli/__main__.py
|
|
11
|
+
magiccampus_cli/accounts.py
|
|
12
|
+
magiccampus_cli/cli.py
|
|
13
|
+
magiccampus_cli/client.py
|
|
14
|
+
magiccampus_cli/config_store.py
|
|
15
|
+
magiccampus_cli/http_send.py
|
|
16
|
+
magiccampus_cli/notify.py
|
|
17
|
+
magiccampus_cli/output.py
|
|
18
|
+
magiccampus_cli/prompts.py
|
|
19
|
+
magiccampus_cli/targets.py
|
|
20
|
+
magiccampus_cli/utils.py
|
|
21
|
+
magiccampus_cli/commands/auth.py
|
|
22
|
+
magiccampus_cli/commands/config.py
|
|
23
|
+
magiccampus_cli/commands/feed.py
|
|
24
|
+
magiccampus_cli/commands/im.py
|
|
25
|
+
magiccampus_cli/commands/notify.py
|
|
26
|
+
magiccampus_cli/commands/user.py
|
|
27
|
+
magiccampus_sdk/__init__.py
|
|
28
|
+
magiccampus_sdk/auth.py
|
|
29
|
+
magiccampus_sdk/client.py
|
|
30
|
+
magiccampus_sdk/example.py
|
|
31
|
+
magiccampus_sdk/example_ws.py
|
|
32
|
+
magiccampus_sdk/feed_client.py
|
|
33
|
+
magiccampus_sdk/models.py
|
|
34
|
+
magiccampus_sdk/platform_client.py
|
|
35
|
+
magiccampus_sdk/platform_http.py
|
|
36
|
+
magiccampus_sdk/platform_ws.py
|
|
37
|
+
magiccampus_sdk/user_client.py
|
|
38
|
+
magiccampus_sdk/user_info_api.py
|
|
39
|
+
magiccampus_sdk/im/__init__.py
|
|
40
|
+
magiccampus_sdk/im/client.py
|
|
41
|
+
magiccampus_sdk/im/gob_codec.py
|
|
42
|
+
magiccampus_sdk/im/http_api.py
|
|
43
|
+
magiccampus_sdk/im/media.py
|
|
44
|
+
magiccampus_sdk/im/models.py
|
|
45
|
+
magiccampus_sdk/im/self_user_info_api.py
|
|
46
|
+
magiccampus_sdk/im/storage.py
|
|
47
|
+
magiccampus_sdk/im/text.py
|
|
48
|
+
magiccampus_sdk/im/ws_client.py
|
|
49
|
+
magiccampus_sdk/im/proto/__init__.py
|
|
50
|
+
magiccampus_sdk/im/proto/sdkws/__init__.py
|
|
51
|
+
magiccampus_sdk/im/proto/sdkws/sdkws_pb2.py
|
|
52
|
+
magiccampus_sdk/im/proto/wrapperspb/__init__.py
|
|
53
|
+
magiccampus_sdk/im/proto/wrapperspb/wrapperspb_pb2.py
|
|
54
|
+
tests/test_auth.py
|
|
55
|
+
tests/test_auth_status.py
|
|
56
|
+
tests/test_cli_config.py
|
|
57
|
+
tests/test_cli_domains.py
|
|
58
|
+
tests/test_cli_interactive.py
|
|
59
|
+
tests/test_cli_main.py
|
|
60
|
+
tests/test_cli_notify.py
|
|
61
|
+
tests/test_im_namespace.py
|
|
62
|
+
tests/test_smoke_cli.py
|
|
63
|
+
tests/test_ws_client.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from magiccampus_sdk.auth import normalize_apiurl, normalize_platform
|
|
6
|
+
|
|
7
|
+
from .utils import env_string, mask_secret, trim_string
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class AccountConfig:
|
|
12
|
+
account_id: str
|
|
13
|
+
enabled: bool
|
|
14
|
+
apiurl: str
|
|
15
|
+
apikey: str
|
|
16
|
+
platform: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def account_config_to_raw(account: AccountConfig) -> dict[str, object]:
|
|
20
|
+
return {
|
|
21
|
+
"enabled": account.enabled,
|
|
22
|
+
"apiUrl": account.apiurl,
|
|
23
|
+
"apiKey": account.apikey,
|
|
24
|
+
"platform": account.platform,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def normalize_stored_account(raw: object) -> dict[str, object]:
|
|
29
|
+
source = raw if isinstance(raw, dict) else {}
|
|
30
|
+
apiurl = trim_string(source.get("apiUrl") or source.get("apiurl"))
|
|
31
|
+
platform = trim_string(source.get("platform")) or "IOS"
|
|
32
|
+
normalized: dict[str, object] = {
|
|
33
|
+
"enabled": source.get("enabled") is not False,
|
|
34
|
+
"apiUrl": normalize_apiurl(apiurl) if apiurl else "",
|
|
35
|
+
"apiKey": trim_string(source.get("apiKey") or source.get("apikey")),
|
|
36
|
+
"platform": normalize_platform(platform),
|
|
37
|
+
}
|
|
38
|
+
return normalized
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def env_default_account() -> dict[str, object] | None:
|
|
42
|
+
apiurl = env_string("MAGICCAMPUS_APIURL")
|
|
43
|
+
apikey = env_string("MAGICCAMPUS_APIKEY")
|
|
44
|
+
if not apiurl or not apikey:
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
"enabled": True,
|
|
49
|
+
"apiUrl": apiurl,
|
|
50
|
+
"apiKey": apikey,
|
|
51
|
+
"platform": env_string("MAGICCAMPUS_PLATFORM") or "IOS",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def normalize_account(account_id: str, raw: object) -> AccountConfig | None:
|
|
56
|
+
stored = normalize_stored_account(raw)
|
|
57
|
+
if not stored["apiUrl"] or not stored["apiKey"]:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
return AccountConfig(
|
|
61
|
+
account_id=account_id,
|
|
62
|
+
enabled=stored.get("enabled") is not False,
|
|
63
|
+
apiurl=str(stored["apiUrl"]),
|
|
64
|
+
apikey=str(stored["apiKey"]),
|
|
65
|
+
platform=str(stored["platform"]),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def list_account_ids(root: dict[str, object]) -> list[str]:
|
|
70
|
+
accounts = root.get("accounts")
|
|
71
|
+
ids = list(accounts.keys()) if isinstance(accounts, dict) else []
|
|
72
|
+
if env_default_account() and "default" not in ids:
|
|
73
|
+
ids.insert(0, "default")
|
|
74
|
+
return ids
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def get_account_config(root: dict[str, object], account_id: str | None) -> AccountConfig | None:
|
|
78
|
+
resolved_id = account_id or str(root.get("defaultAccountId") or "default")
|
|
79
|
+
if resolved_id == "default":
|
|
80
|
+
env_account = env_default_account()
|
|
81
|
+
if env_account is not None:
|
|
82
|
+
return normalize_account("default", env_account)
|
|
83
|
+
|
|
84
|
+
accounts = root.get("accounts")
|
|
85
|
+
configured = accounts.get(resolved_id) if isinstance(accounts, dict) else None
|
|
86
|
+
if configured is not None:
|
|
87
|
+
return normalize_account(resolved_id, configured)
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def list_account_summaries(root: dict[str, object]) -> list[dict[str, object]]:
|
|
92
|
+
summaries: list[dict[str, object]] = []
|
|
93
|
+
default_account_id = str(root.get("defaultAccountId") or "default")
|
|
94
|
+
for account_id in list_account_ids(root):
|
|
95
|
+
account = get_account_config(root, account_id)
|
|
96
|
+
if account is None:
|
|
97
|
+
continue
|
|
98
|
+
summaries.append(
|
|
99
|
+
{
|
|
100
|
+
"accountId": account.account_id,
|
|
101
|
+
"default": account.account_id == default_account_id,
|
|
102
|
+
"enabled": account.enabled,
|
|
103
|
+
"apiUrl": account.apiurl,
|
|
104
|
+
"platform": account.platform,
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
return summaries
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def upsert_stored_account(root: dict[str, object], account_id: str, raw_account: dict[str, object], make_default: bool = False) -> dict[str, object]:
|
|
111
|
+
accounts = root.get("accounts")
|
|
112
|
+
next_accounts = dict(accounts) if isinstance(accounts, dict) else {}
|
|
113
|
+
next_accounts[account_id] = normalize_stored_account(raw_account)
|
|
114
|
+
default_account_id = account_id if make_default else str(root.get("defaultAccountId") or account_id)
|
|
115
|
+
return {"defaultAccountId": default_account_id, "accounts": next_accounts}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def remove_stored_account(root: dict[str, object], account_id: str) -> dict[str, object]:
|
|
119
|
+
accounts = root.get("accounts")
|
|
120
|
+
next_accounts = dict(accounts) if isinstance(accounts, dict) else {}
|
|
121
|
+
next_accounts.pop(account_id, None)
|
|
122
|
+
remaining_ids = list(next_accounts.keys())
|
|
123
|
+
default_account_id = str(root.get("defaultAccountId") or "default")
|
|
124
|
+
if default_account_id == account_id:
|
|
125
|
+
default_account_id = remaining_ids[0] if remaining_ids else "default"
|
|
126
|
+
return {"defaultAccountId": default_account_id, "accounts": next_accounts}
|