@@ -291,6 +291,31 @@ internal Task<RestResponse> DoRequestAsync(BaseDiscordClient client, RateLimitBu
291291 return req . WaitForCompletionAsync ( ) ;
292292 }
293293
294+ /// <summary>
295+ /// Executes a rest request directly, bypassing the bucket worker queue.
296+ /// Used for latency-sensitive endpoints like interaction callbacks.
297+ /// </summary>
298+ /// <param name="client">The client.</param>
299+ /// <param name="bucket">The bucket.</param>
300+ /// <param name="url">The url.</param>
301+ /// <param name="method">The method.</param>
302+ /// <param name="route">The route.</param>
303+ /// <param name="headers">The headers.</param>
304+ /// <param name="payload">The payload.</param>
305+ /// <param name="ratelimitWaitOverride">The ratelimit wait override.</param>
306+ /// <param name="cancellationToken">A token to cancel the request.</param>
307+ internal Task < RestResponse > DoDirectRequestAsync ( BaseDiscordClient client , RateLimitBucket bucket , Uri url , RestRequestMethod method , string route , IReadOnlyDictionary < string , string > ? headers = null , string ? payload = null , double ? ratelimitWaitOverride = null , CancellationToken cancellationToken = default )
308+ {
309+ var req = new RestRequest ( client , bucket , url , method , route , headers , payload , ratelimitWaitOverride , cancellationToken : cancellationToken ) ;
310+
311+ if ( this . Discord is not null )
312+ this . Rest . ExecuteDirectAsync ( req ) . LogTaskFault ( this . Discord . Logger , LogLevel . Error , LoggerEvents . RestError , $ "Error while executing direct request. Url: { url . AbsoluteUri } ") ;
313+ else
314+ _ = this . Rest . ExecuteDirectAsync ( req ) ;
315+
316+ return req . WaitForCompletionAsync ( ) ;
317+ }
318+
294319 /// <summary>
295320 /// Builds a CSV file for target users from the provided user ids.
296321 /// </summary>
@@ -518,6 +543,47 @@ private Task<RestResponse> DoMultipartAsync(
518543 return req . WaitForCompletionAsync ( ) ;
519544 }
520545
546+ /// <summary>
547+ /// Executes a multipart request directly, bypassing the bucket worker queue.
548+ /// Used for latency-sensitive endpoints like interaction callbacks with file uploads.
549+ /// </summary>
550+ /// <param name="client">The client.</param>
551+ /// <param name="bucket">The bucket.</param>
552+ /// <param name="url">The url.</param>
553+ /// <param name="method">The method.</param>
554+ /// <param name="route">The route.</param>
555+ /// <param name="headers">The headers.</param>
556+ /// <param name="values">The values.</param>
557+ /// <param name="files">The files.</param>
558+ /// <param name="ratelimitWaitOverride">The ratelimit wait override.</param>
559+ /// <param name="overwriteFileIdStart">The file id start to overwrite.</param>
560+ /// <param name="fileFieldNameFactory">The factory function to generate file field names.</param>
561+ /// <param name="cancellationToken">A token to cancel the request.</param>
562+ private Task < RestResponse > DoDirectMultipartAsync (
563+ BaseDiscordClient client ,
564+ RateLimitBucket bucket ,
565+ Uri url ,
566+ RestRequestMethod method ,
567+ string route ,
568+ IReadOnlyDictionary < string , string > ? headers = null ,
569+ IReadOnlyDictionary < string , string > ? values = null ,
570+ IEnumerable < DiscordMessageFile > ? files = null ,
571+ double ? ratelimitWaitOverride = null ,
572+ int ? overwriteFileIdStart = null ,
573+ Func < int , string > ? fileFieldNameFactory = null ,
574+ CancellationToken cancellationToken = default
575+ )
576+ {
577+ var req = new MultipartWebRequest ( client , bucket , url , method , route , headers , values , files , ratelimitWaitOverride , overwriteFileIdStart , fileFieldNameFactory , cancellationToken ) ;
578+
579+ if ( this . Discord is not null )
580+ this . Rest . ExecuteDirectAsync ( req ) . LogTaskFault ( this . Discord . Logger , LogLevel . Error , LoggerEvents . RestError , "Error while executing direct request" ) ;
581+ else
582+ _ = this . Rest . ExecuteDirectAsync ( req ) ;
583+
584+ return req . WaitForCompletionAsync ( ) ;
585+ }
586+
521587 /// <summary>
522588 /// Executes a multipart request.
523589 /// </summary>
@@ -8104,14 +8170,14 @@ internal async Task<DiscordInteractionCallbackResponse> CreateInteractionRespons
81048170 var url = Utilities . GetApiUriBuilderFor ( path , this . Discord . Configuration ) . AddParameter ( "wait" , "false" ) . AddParameter ( "with_response" , "true" ) . Build ( ) ;
81058171 if ( builder is not null && builder . Files is not null && values . Count is not 0 )
81068172 {
8107- response = await this . DoMultipartAsync ( this . Discord , bucket , url , RestRequestMethod . POST , route , values : values , files : builder . Files , cancellationToken : cancellationToken ) . ConfigureAwait ( false ) ;
8173+ response = await this . DoDirectMultipartAsync ( this . Discord , bucket , url , RestRequestMethod . POST , route , values : values , files : builder . Files , cancellationToken : cancellationToken ) . ConfigureAwait ( false ) ;
81088174
81098175 if ( builder . Files is not null )
81108176 foreach ( var file in builder . Files . Where ( x => x . ResetPositionTo . HasValue ) )
81118177 file. Stream . Position = file . ResetPositionTo ! . Value ;
81128178 }
81138179 else
8114- response = await this . DoRequestAsync ( this . Discord , bucket , url , RestRequestMethod . POST , route , payload : DiscordJson . SerializeObject ( pld ) , cancellationToken : cancellationToken ) . ConfigureAwait ( false ) ;
8180+ response = await this . DoDirectRequestAsync ( this . Discord , bucket , url , RestRequestMethod . POST , route , payload : DiscordJson . SerializeObject ( pld ) , cancellationToken : cancellationToken ) . ConfigureAwait ( false ) ;
81158181
81168182 return response . ResponseCode is not HttpStatusCode . NoContent && ! string . IsNullOrEmpty ( response . Response )
81178183 ? DiscordJson . DeserializeObject < DiscordInteractionCallbackResponse > ( response . Response , this . Discord )
@@ -8155,7 +8221,7 @@ internal async Task CreateInteractionModalResponseAsync(ulong interactionId, str
81558221 } , out var path ) ;
81568222
81578223 var url = Utilities. GetApiUriBuilderFor ( path , this . Discord . Configuration ) . AddParameter ( "wait" , "true" ) . Build ( ) ;
8158- await this . DoRequestAsync ( this . Discord , bucket , url , RestRequestMethod . POST , route , payload : DiscordJson . SerializeObject ( pld ) , cancellationToken : cancellationToken ) . ConfigureAwait ( false ) ;
8224+ await this . DoDirectRequestAsync ( this . Discord , bucket , url , RestRequestMethod . POST , route , payload : DiscordJson . SerializeObject ( pld ) , cancellationToken : cancellationToken ) . ConfigureAwait ( false ) ;
81598225 }
81608226
81618227 /// <summary>
@@ -8193,7 +8259,7 @@ internal async Task CreateInteractionIframeResponseAsync(ulong interactionId, st
81938259 } , out var path ) ;
81948260
81958261 var url = Utilities. GetApiUriBuilderFor ( path , this . Discord . Configuration ) . AddParameter ( "wait" , "true" ) . Build ( ) ;
8196- await this . DoRequestAsync ( this . Discord , bucket , url , RestRequestMethod . POST , route , payload : DiscordJson . SerializeObject ( pld ) , cancellationToken : cancellationToken ) . ConfigureAwait ( false ) ;
8262+ await this . DoDirectRequestAsync ( this . Discord , bucket , url , RestRequestMethod . POST , route , payload : DiscordJson . SerializeObject ( pld ) , cancellationToken : cancellationToken ) . ConfigureAwait ( false ) ;
81978263 }
81988264
81998265 /// <summary>
0 commit comments