|
1 | 1 | # BotApi |
2 | 2 |
|
3 | | -`BotApi` is the synchronous-style facade over the QQ Bot Open API. It owns the HTTP client, builds requests, signs them with a `Token`, and returns parsed model types. Every method is `async` and returns `Result<T, BotError>`. |
| 3 | +`BotApi` is the REST client used by a bot while handling events. After a gateway event arrives, handlers usually call it through `Context` to send replies, recall channel messages, upload group/C2C files, manage announcements, schedules and pins, inspect reaction users, or create API permission requests. |
4 | 4 |
|
5 | | -## Construction |
| 5 | +When your bot is driven by `Client`, you normally do not construct `BotApi` yourself. Every event callback receives a `Context` that already owns the shared API client: |
6 | 6 |
|
7 | 7 | ```rust |
8 | | -use botrs::{BotApi, http::HttpClient, Token}; |
| 8 | +let params = MessageParams::new_text("pong").with_reply(message_id); |
| 9 | +ctx.send_message(&channel_id, params).await?; |
| 10 | +``` |
| 11 | + |
| 12 | +Construct `BotApi` manually only when you want to call REST without running the gateway: |
9 | 13 |
|
10 | | -let http = HttpClient::new(/* timeout secs */ 30, /* sandbox */ false)?; |
| 14 | +```rust |
| 15 | +let http = HttpClient::new(30, false)?; |
11 | 16 | let token = Token::new("app_id", "secret"); |
12 | 17 | let api = BotApi::new(http, token); |
13 | 18 |
|
14 | 19 | let me = api.get_bot_info().await?; |
15 | 20 | ``` |
16 | 21 |
|
17 | | -`BotApi` is `Clone` and cheap to clone; the inner HTTP client is reference-counted. For a bot client driven by `Client`, `Context` dereferences to the same `BotApi`, so handler code can call `ctx.send_message(...)` directly. |
18 | | - |
19 | | -## Method index |
20 | | - |
21 | | -Every method takes `&self` plus endpoint-specific arguments and returns `Result<…>`. The token is stored on `BotApi`. The lists below group the 100+ routes by domain. Look up parameter and response types in [Models](./models/messages.md), [Guilds & Channels](./models/guilds-channels.md), and [Other Types](./models/other-types.md). |
22 | | - |
23 | | -### Bot identity |
24 | | - |
25 | | -- `get_bot_info` — `/users/@me`, returns `BotInfo`. |
26 | | -- `get_gateway` — gateway URL + recommended shard count. |
27 | | - |
28 | | -### Guilds |
29 | | - |
30 | | -- `get_guild` / `get_guilds` / `get_guilds_with_pager` |
31 | | -- guild members: `get_guild_member`, `get_guild_members`, `get_guild_members_with_pager` |
32 | | -- role members: `get_guild_role_members`, `get_guild_role_members_with_pager` |
33 | | -- mute: `mute_all`, `cancel_mute_all`, `mute_member`, `mute_multi_member`, `multi_member_mute`, `cancel_mute_multi_member` |
34 | | - |
35 | | -### Channels |
36 | | - |
37 | | -- `get_channel`, `get_channels` |
38 | | -- `create_channel`, `create_private_channel`, `update_channel`, `delete_channel` |
39 | | -- permissions: `get_channel_user_permissions`, `get_channel_role_permissions`, `update_channel_user_permissions`, `update_channel_role_permissions`, `put_channel_permissions`, `put_channel_roles_permissions` |
40 | | - |
41 | | -### Roles |
42 | | - |
43 | | -- `get_guild_roles` |
44 | | -- `create_guild_role`, `update_guild_role`, `delete_guild_role` |
45 | | -- assign / remove: `create_guild_role_member`, `delete_guild_role_member`, `delete_member`, `delete_member_with_options` |
46 | | - |
47 | | -### Messages (channel) |
48 | | - |
49 | | -- `get_message`, `get_messages` |
50 | | -- send: `send_message`. |
51 | | -- edit: `edit_message`. |
52 | | -- recall: `recall_message`. |
53 | | - |
54 | | -### Direct messages |
55 | | - |
56 | | -- create session: `create_direct_message`. |
57 | | -- send: `send_direct_message`. |
58 | | -- recall: `retract_dm_message`. |
59 | | -- setting guide: `post_dm_setting_guide`, `post_dm_setting_guide_message`. |
60 | | - |
61 | | -### Group / C2C messages |
62 | | - |
63 | | -- send: `send_group_message`, `send_c2c_message`. |
64 | | -- recall: `retract_group_message`, `retract_c2c_message`. |
65 | | -- file upload: `post_group_file`, `post_c2c_file`. |
66 | | - |
67 | | -### Reactions |
68 | | - |
69 | | -- `put_reaction`, `delete_reaction`, `delete_own_message_reaction` |
70 | | -- `create_message_reaction`, `get_reaction_users`, `get_message_reaction_users` |
71 | | - |
72 | | -### Pins |
| 22 | +## Current Surface |
73 | 23 |
|
74 | | -- `put_pin`, `delete_pin`, `get_pins`, `clean_pins` |
| 24 | +`BotApi` covers these paths: |
75 | 25 |
|
76 | | -### Announces |
| 26 | +| Area | Methods | |
| 27 | +| --- | --- | |
| 28 | +| Bot identity and gateway discovery | `get_bot_info`, `get_gateway` | |
| 29 | +| Guild channel messages | `send_message`, `recall_message` | |
| 30 | +| Group and C2C messages | `send_group_message`, `send_c2c_message` | |
| 31 | +| Direct messages | `create_direct_message`, `send_direct_message` | |
| 32 | +| Group/C2C files | `post_group_file`, `post_c2c_file` | |
| 33 | +| Announcements | `create_announce`, `create_recommend_announce`, `delete_announce` | |
| 34 | +| Schedules | `get_schedules`, `get_schedule`, `create_schedule`, `update_schedule`, `delete_schedule` | |
| 35 | +| API permissions | `get_api_permissions`, `post_permission_demand` | |
| 36 | +| Reactions | `put_reaction`, `delete_reaction`, `get_reaction_users` | |
| 37 | +| Pins | `put_pin`, `delete_pin`, `get_pins` | |
77 | 38 |
|
78 | | -- guild: `create_guild_announce`, `delete_guild_announce`, `clean_guild_announces`, `create_guild_recommend_announce`, `create_recommend_announce` |
79 | | -- channel: `create_channel_announce`, `delete_channel_announce`, `clean_channel_announces` |
80 | | -- shorthand: `create_announce`, `delete_announce` |
| 39 | +## Sending Messages |
81 | 40 |
|
82 | | -### Schedules |
| 41 | +Message sending uses parameter structs: |
83 | 42 |
|
84 | | -- `get_schedules`, `get_schedule`, `create_schedule`, `update_schedule`, `delete_schedule` |
85 | | - |
86 | | -### API permissions |
87 | | - |
88 | | -- `get_api_permissions`, `post_permission_demand`, `require_api_permissions` |
89 | | - |
90 | | -### Audio / voice |
91 | | - |
92 | | -- `post_audio` (uses `AudioControl`), `update_audio` |
93 | | -- `on_microphone`, `off_microphone`, `list_voice_channel_members` |
| 43 | +```rust |
| 44 | +let params = MessageParams::new_text("hello"); |
| 45 | +ctx.send_message(&channel_id, params).await?; |
94 | 46 |
|
95 | | -### Setting guide |
| 47 | +let params = GroupMessageParams::new_text("hello group"); |
| 48 | +ctx.send_group_message(&group_openid, params).await?; |
| 49 | +``` |
96 | 50 |
|
97 | | -- `post_setting_guide`, `post_setting_guide_message` |
| 51 | +Guild channel messages and DMs use `MessageParams` / `DirectMessageParams`. Group and C2C messages use `GroupMessageParams` / `C2CMessageParams`, matching QQ's open-message shape. For ark, embed, markdown, keyboard, or media payloads, set the corresponding field on the parameter struct. |
98 | 52 |
|
99 | | -### Interaction |
| 53 | +## Files and Media |
100 | 54 |
|
101 | | -- `put_interaction` — acknowledges a button/interaction event. |
| 55 | +Group and C2C media sending is a two-step flow: upload the file to receive a `Media`, then place that media object into a message parameter struct. `file_type` follows the platform values: commonly 1 image, 2 video, 3 audio, 4 file. |
102 | 56 |
|
103 | | -### Webhook sessions |
| 57 | +```rust |
| 58 | +let media = ctx |
| 59 | + .post_group_file(&group_openid, 1, "https://example.com/image.png", None) |
| 60 | + .await?; |
104 | 61 |
|
105 | | -- `create_session`, `check_sessions`, `session_list`, `remove_session` |
| 62 | +let mut params = GroupMessageParams::default(); |
| 63 | +params.msg_type = 7; |
| 64 | +params.media = Some(media); |
| 65 | +ctx.send_group_message(&group_openid, params).await?; |
| 66 | +``` |
106 | 67 |
|
107 | | -### Message setting |
| 68 | +When `srv_send_msg` is `Some(true)`, the platform sends the uploaded file directly, so you usually do not need a separate media message. |
108 | 69 |
|
109 | | -- `get_message_setting` — guild push and DM toggles. |
| 70 | +## Announcements, Schedules, Pins, Permissions |
110 | 71 |
|
111 | | -## Worked examples |
| 72 | +These APIs are direct wrappers around their protocol payloads: |
112 | 73 |
|
113 | | -**Reply to an @-mention with a keyboard.** Build the keyboard once, attach to `MessageParams`, and dispatch with `send_message`. |
| 74 | +- Announcements can be created from an existing message or from a list of recommended channels. |
| 75 | +- Schedules support listing, fetching one item, creating, updating, and deleting. |
| 76 | +- Pins support pinning one message, unpinning one message, and listing pinned message ids. |
| 77 | +- API permission requests take `channel_id`, `APIPermissionDemandIdentify`, and a description. |
114 | 78 |
|
115 | 79 | ```rust |
116 | | -let keyboard = Keyboard { |
117 | | - content: Some(KeyboardContent { |
118 | | - rows: Some(vec![KeyboardRow { |
119 | | - buttons: Some(vec![KeyboardButton { |
120 | | - id: Some("ok".into()), |
121 | | - render_data: Some(KeyboardButtonRenderData { |
122 | | - label: Some("OK".into()), |
123 | | - style: Some(1), |
124 | | - ..Default::default() |
125 | | - }), |
126 | | - action: Some(KeyboardButtonAction { |
127 | | - action_type: Some(1), |
128 | | - permission: Some(KeyboardButtonPermission { |
129 | | - permission_type: Some(2), |
130 | | - ..Default::default() |
131 | | - }), |
132 | | - data: Some("ok".into()), |
133 | | - ..Default::default() |
134 | | - }), |
135 | | - ..Default::default() |
136 | | - }]), |
137 | | - }]), |
138 | | - ..Default::default() |
139 | | - }), |
140 | | - ..Default::default() |
| 80 | +let identify = APIPermissionDemandIdentify { |
| 81 | + path: "/channels/{channel_id}/messages".to_string(), |
| 82 | + method: "POST".to_string(), |
141 | 83 | }; |
142 | 84 |
|
143 | | -let mut params = MessageParams::new_text("Choose:") |
144 | | - .with_reply(message.id.as_deref().unwrap_or("")); |
145 | | -params.keyboard = Some(keyboard); |
146 | | - |
147 | | -api.send_message(&channel_id, params).await?; |
148 | | -``` |
149 | | - |
150 | | -**Paginated member listing.** Use the pager helper to avoid manually threading `after`. |
151 | | - |
152 | | -```rust |
153 | | -let pager = ctx |
154 | | - .get_guild_members_with_pager(&guild_id, &GuildMembersPager::default()) |
| 85 | +ctx.post_permission_demand(&guild_id, &channel_id, identify, "Need to send replies") |
155 | 86 | .await?; |
156 | | -for member in pager.items { |
157 | | - /* ... */ |
158 | | -} |
159 | 87 | ``` |
160 | 88 |
|
161 | | -**Update channel permissions safely.** The `validate()` helper rejects non-numeric strings before they reach the server. |
| 89 | +## Errors |
| 90 | + |
| 91 | +All methods return `botrs::Result<T>`. In event handlers, handle errors locally because `EventHandler` methods return `()`: |
162 | 92 |
|
163 | 93 | ```rust |
164 | | -let body = UpdateChannelPermissions::new(Some("1024"), Some("0")); |
165 | | -body.validate()?; |
166 | | -api.update_channel_user_permissions(&channel_id, &user_id, &body).await?; |
| 94 | +if let Err(err) = ctx.send_message(&channel_id, params).await { |
| 95 | + tracing::warn!("send failed: {err}"); |
| 96 | +} |
167 | 97 | ``` |
168 | 98 |
|
169 | | -## Error handling |
170 | | - |
171 | | -Every call returns `Result<T, BotError>`. Match on `BotError` to distinguish: |
172 | | - |
173 | | -- `BotError::Http` — transport-level failures (timeout, DNS). |
174 | | -- `BotError::Api { code, message, .. }` — non-2xx response with the QQ-defined error code. |
175 | | -- `BotError::Auth` — token signing or refresh failure. |
176 | | -- `BotError::InvalidData` — local validation failure (e.g. malformed permission string). |
177 | | - |
178 | | -For 429 responses, `BotError::Api` carries the `Retry-After` hint when present; the framework does not retry automatically — wrap calls with your own backoff if you need that behavior. |
179 | | - |
180 | | -## See also |
| 99 | +## See Also |
181 | 100 |
|
182 | | -- [Client](./client.md) — high-level bot loop that owns a `BotApi`. |
183 | | -- [Context](./context.md) — request-scoped wrapper exposing the same routes during event handling. |
184 | | -- [Models](./models/messages.md) — request and response struct definitions. |
185 | | -- [Token](./token.md) — credential management and refresh. |
| 101 | +- [Context](./context.md) |
| 102 | +- [Messages](./models/messages.md) |
| 103 | +- [Other types](./models/other-types.md) |
0 commit comments