62
62
"MessageInteraction" ,
63
63
"InteractionMetadata" ,
64
64
"AuthorizingIntegrationOwners" ,
65
+ "InteractionCallback" ,
65
66
)
66
67
67
68
if TYPE_CHECKING :
84
85
from .state import ConnectionState
85
86
from .threads import Thread
86
87
from .types .interactions import Interaction as InteractionPayload
87
- from .types .interactions import InteractionData
88
+ from .types .interactions import InteractionCallback as InteractionCallbackPayload
89
+ from .types .interactions import InteractionCallbackResponse , InteractionData
88
90
from .types .interactions import InteractionMetadata as InteractionMetadataPayload
89
91
from .types .interactions import MessageInteraction as MessageInteractionPayload
90
92
from .ui .modal import Modal
@@ -154,6 +156,11 @@ class Interaction:
154
156
The context in which this command was executed.
155
157
156
158
.. versionadded:: 2.6
159
+ callback: Optional[:class:`InteractionCallback`]
160
+ The callback of the interaction. Contains information about the status of the interaction response.
161
+ Will be `None` until the interaction is responded to.
162
+
163
+ .. versionadded:: 2.7
157
164
command: Optional[:class:`ApplicationCommand`]
158
165
The command that this interaction belongs to.
159
166
@@ -190,6 +197,7 @@ class Interaction:
190
197
"entitlements" ,
191
198
"context" ,
192
199
"authorizing_integration_owners" ,
200
+ "callback" ,
193
201
"command" ,
194
202
"view" ,
195
203
"modal" ,
@@ -213,6 +221,7 @@ def __init__(self, *, data: InteractionPayload, state: ConnectionState):
213
221
self ._state : ConnectionState = state
214
222
self ._session : ClientSession = state .http ._HTTPClient__session
215
223
self ._original_response : InteractionMessage | None = None
224
+ self .callback : InteractionCallback | None = None
216
225
self ._from_data (data )
217
226
218
227
def _from_data (self , data : InteractionPayload ):
@@ -443,7 +452,9 @@ async def original_response(self) -> InteractionMessage:
443
452
# TODO: fix later to not raise?
444
453
channel = self .channel
445
454
if channel is None :
446
- raise ClientException ("Channel for message could not be resolved" )
455
+ raise ClientException (
456
+ "Channel for message could not be resolved. Please open a issue on GitHub if you encounter this error."
457
+ )
447
458
448
459
adapter = async_context .get ()
449
460
http = self ._state .http
@@ -828,18 +839,21 @@ async def defer(self, *, ephemeral: bool = False, invisible: bool = True) -> Non
828
839
if defer_type :
829
840
adapter = async_context .get ()
830
841
http = parent ._state .http
831
- await self ._locked_response (
832
- adapter .create_interaction_response (
833
- parent .id ,
834
- parent .token ,
835
- session = parent ._session ,
836
- type = defer_type ,
837
- data = data ,
838
- proxy = http .proxy ,
839
- proxy_auth = http .proxy_auth ,
842
+ callback_response : InteractionCallbackResponse = (
843
+ await self ._locked_response (
844
+ adapter .create_interaction_response (
845
+ parent .id ,
846
+ parent .token ,
847
+ session = parent ._session ,
848
+ type = defer_type ,
849
+ data = data ,
850
+ proxy = http .proxy ,
851
+ proxy_auth = http .proxy_auth ,
852
+ )
840
853
)
841
854
)
842
855
self ._responded = True
856
+ await self ._process_callback_response (callback_response )
843
857
844
858
async def pong (self ) -> None :
845
859
"""|coro|
@@ -862,17 +876,36 @@ async def pong(self) -> None:
862
876
if parent .type is InteractionType .ping :
863
877
adapter = async_context .get ()
864
878
http = parent ._state .http
865
- await self ._locked_response (
866
- adapter .create_interaction_response (
867
- parent .id ,
868
- parent .token ,
869
- session = parent ._session ,
870
- proxy = http .proxy ,
871
- proxy_auth = http .proxy_auth ,
872
- type = InteractionResponseType .pong .value ,
879
+ callback_response : InteractionCallbackResponse = (
880
+ await self ._locked_response (
881
+ adapter .create_interaction_response (
882
+ parent .id ,
883
+ parent .token ,
884
+ session = parent ._session ,
885
+ proxy = http .proxy ,
886
+ proxy_auth = http .proxy_auth ,
887
+ type = InteractionResponseType .pong .value ,
888
+ )
873
889
)
874
890
)
875
891
self ._responded = True
892
+ await self ._process_callback_response (callback_response )
893
+
894
+ async def _process_callback_response (
895
+ self , callback_response : InteractionCallbackResponse
896
+ ):
897
+ if callback_response .get ("resource" , {}).get ("message" ):
898
+ # TODO: fix later to not raise?
899
+ channel = self ._parent .channel
900
+ if channel is None :
901
+ raise ClientException (
902
+ "Channel for message could not be resolved. Please open a issue on GitHub if you encounter this error."
903
+ )
904
+ state = _InteractionMessageState (self ._parent , self ._parent ._state )
905
+ message = InteractionMessage (state = state , channel = channel , data = callback_response ["resource" ]["message" ]) # type: ignore
906
+ self ._parent ._original_response = message
907
+
908
+ self ._parent .callback = InteractionCallback (callback_response ["interaction" ])
876
909
877
910
async def send_message (
878
911
self ,
@@ -1008,16 +1041,18 @@ async def send_message(
1008
1041
adapter = async_context .get ()
1009
1042
http = parent ._state .http
1010
1043
try :
1011
- await self ._locked_response (
1012
- adapter .create_interaction_response (
1013
- parent .id ,
1014
- parent .token ,
1015
- session = parent ._session ,
1016
- type = InteractionResponseType .channel_message .value ,
1017
- proxy = http .proxy ,
1018
- proxy_auth = http .proxy_auth ,
1019
- data = payload ,
1020
- files = files ,
1044
+ callback_response : InteractionCallbackResponse = (
1045
+ await self ._locked_response (
1046
+ adapter .create_interaction_response (
1047
+ parent .id ,
1048
+ parent .token ,
1049
+ session = parent ._session ,
1050
+ type = InteractionResponseType .channel_message .value ,
1051
+ proxy = http .proxy ,
1052
+ proxy_auth = http .proxy_auth ,
1053
+ data = payload ,
1054
+ files = files ,
1055
+ )
1021
1056
)
1022
1057
)
1023
1058
finally :
@@ -1034,6 +1069,7 @@ async def send_message(
1034
1069
self ._parent ._state .store_view (view )
1035
1070
1036
1071
self ._responded = True
1072
+ await self ._process_callback_response (callback_response )
1037
1073
if delete_after is not None :
1038
1074
await self ._parent .delete_original_response (delay = delete_after )
1039
1075
return self ._parent
@@ -1165,16 +1201,18 @@ async def edit_message(
1165
1201
adapter = async_context .get ()
1166
1202
http = parent ._state .http
1167
1203
try :
1168
- await self ._locked_response (
1169
- adapter .create_interaction_response (
1170
- parent .id ,
1171
- parent .token ,
1172
- session = parent ._session ,
1173
- type = InteractionResponseType .message_update .value ,
1174
- proxy = http .proxy ,
1175
- proxy_auth = http .proxy_auth ,
1176
- data = payload ,
1177
- files = files ,
1204
+ callback_response : InteractionCallbackResponse = (
1205
+ await self ._locked_response (
1206
+ adapter .create_interaction_response (
1207
+ parent .id ,
1208
+ parent .token ,
1209
+ session = parent ._session ,
1210
+ type = InteractionResponseType .message_update .value ,
1211
+ proxy = http .proxy ,
1212
+ proxy_auth = http .proxy_auth ,
1213
+ data = payload ,
1214
+ files = files ,
1215
+ )
1178
1216
)
1179
1217
)
1180
1218
finally :
@@ -1187,6 +1225,7 @@ async def edit_message(
1187
1225
state .store_view (view , message_id )
1188
1226
1189
1227
self ._responded = True
1228
+ await self ._process_callback_response (callback_response )
1190
1229
if delete_after is not None :
1191
1230
await self ._parent .delete_original_response (delay = delete_after )
1192
1231
@@ -1222,7 +1261,7 @@ async def send_autocomplete_result(
1222
1261
1223
1262
adapter = async_context .get ()
1224
1263
http = parent ._state .http
1225
- await self ._locked_response (
1264
+ callback_response : InteractionCallbackResponse = await self ._locked_response (
1226
1265
adapter .create_interaction_response (
1227
1266
parent .id ,
1228
1267
parent .token ,
@@ -1235,6 +1274,7 @@ async def send_autocomplete_result(
1235
1274
)
1236
1275
1237
1276
self ._responded = True
1277
+ await self ._process_callback_response (callback_response )
1238
1278
1239
1279
async def send_modal (self , modal : Modal ) -> Interaction :
1240
1280
"""|coro|
@@ -1261,7 +1301,7 @@ async def send_modal(self, modal: Modal) -> Interaction:
1261
1301
payload = modal .to_dict ()
1262
1302
adapter = async_context .get ()
1263
1303
http = parent ._state .http
1264
- await self ._locked_response (
1304
+ callback_response : InteractionCallbackResponse = await self ._locked_response (
1265
1305
adapter .create_interaction_response (
1266
1306
parent .id ,
1267
1307
parent .token ,
@@ -1273,6 +1313,7 @@ async def send_modal(self, modal: Modal) -> Interaction:
1273
1313
)
1274
1314
)
1275
1315
self ._responded = True
1316
+ await self ._process_callback_response (callback_response )
1276
1317
self ._parent ._state .store_modal (modal , self ._parent .user .id )
1277
1318
return self ._parent
1278
1319
@@ -1300,7 +1341,7 @@ async def premium_required(self) -> Interaction:
1300
1341
1301
1342
adapter = async_context .get ()
1302
1343
http = parent ._state .http
1303
- await self ._locked_response (
1344
+ callback_response : InteractionCallbackResponse = await self ._locked_response (
1304
1345
adapter .create_interaction_response (
1305
1346
parent .id ,
1306
1347
parent .token ,
@@ -1311,9 +1352,10 @@ async def premium_required(self) -> Interaction:
1311
1352
)
1312
1353
)
1313
1354
self ._responded = True
1355
+ await self ._process_callback_response (callback_response )
1314
1356
return self ._parent
1315
1357
1316
- async def _locked_response (self , coro : Coroutine [Any , Any , Any ]) -> None :
1358
+ async def _locked_response (self , coro : Coroutine [Any , Any , Any ]) -> Any :
1317
1359
"""|coro|
1318
1360
1319
1361
Wraps a response and makes sure that it's locked while executing.
@@ -1323,16 +1365,24 @@ async def _locked_response(self, coro: Coroutine[Any, Any, Any]) -> None:
1323
1365
coro: Coroutine[Any]
1324
1366
The coroutine to wrap.
1325
1367
1368
+ Returns
1369
+ -------
1370
+ Any
1371
+ The result of the coroutine.
1372
+
1326
1373
Raises
1327
1374
------
1328
1375
InteractionResponded
1329
1376
This interaction has already been responded to before.
1377
+
1378
+ .. versionchanged:: 2.7
1379
+ Return the result of the coroutine
1330
1380
"""
1331
1381
async with self ._response_lock :
1332
1382
if self .is_done ():
1333
1383
coro .close () # cleanup un-awaited coroutine
1334
1384
raise InteractionResponded (self ._parent )
1335
- await coro
1385
+ return await coro
1336
1386
1337
1387
1338
1388
class _InteractionMessageState :
@@ -1646,3 +1696,36 @@ def guild(self) -> Guild | None:
1646
1696
if not self .guild_id :
1647
1697
return None
1648
1698
return self ._state ._get_guild (self .guild_id )
1699
+
1700
+
1701
+ class InteractionCallback :
1702
+ """Information about the status of the interaction response.
1703
+
1704
+ .. versionadded:: 2.7
1705
+ """
1706
+
1707
+ def __init__ (self , data : InteractionCallbackPayload ):
1708
+ self ._response_message_loading : bool = data .get (
1709
+ "response_message_loading" , False
1710
+ )
1711
+ self ._response_message_ephemeral : bool = data .get (
1712
+ "response_message_ephemeral" , False
1713
+ )
1714
+
1715
+ def __repr__ (self ):
1716
+ return (
1717
+ f"<InteractionCallback "
1718
+ f"_response_message_loading={ self ._response_message_loading } "
1719
+ f"_response_message_ephemeral={ self ._response_message_ephemeral } >"
1720
+ )
1721
+
1722
+ def is_loading (self ) -> bool :
1723
+ """Indicates whether the response message is in a loading state."""
1724
+ return self ._response_message_loading
1725
+
1726
+ def is_ephemeral (self ) -> bool :
1727
+ """Indicates whether the response message is ephemeral.
1728
+
1729
+ This might be useful for determining if the message was forced to be ephemeral.
1730
+ """
1731
+ return self ._response_message_ephemeral
0 commit comments