@@ -13,13 +13,15 @@ use anyhow::Result;
1313use discord_nats:: { subjects, MessagePublisher , MessageSubscriber } ;
1414use discord_types:: {
1515 AddReactionCommand , ArchiveThreadCommand , AssignRoleCommand , AutocompleteRespondCommand ,
16- BanUserCommand , BulkDeleteMessagesCommand , CreateChannelCommand , CreateRoleCommand ,
17- CreateThreadCommand , CreateWebhookCommand , DeleteChannelCommand , DeleteMessageCommand ,
18- DeleteRoleCommand , DeleteWebhookCommand , EditChannelCommand , EditMessageCommand ,
19- ExecuteWebhookCommand , FetchMemberCommand , FetchMessagesCommand , GuildMemberNickCommand ,
20- InteractionDeferCommand , InteractionFollowupCommand , InteractionRespondCommand , KickUserCommand ,
21- ModalRespondCommand , PinMessageCommand , RemoveReactionCommand , RemoveRoleCommand ,
22- SendMessageCommand , SetBotPresenceCommand , TimeoutUserCommand , TypingCommand , UnbanUserCommand ,
16+ BanUserCommand , BulkDeleteMessagesCommand , CreateChannelCommand , CreateEmojiCommand ,
17+ CreateInviteCommand , CreateRoleCommand , CreateScheduledEventCommand , CreateThreadCommand ,
18+ CreateWebhookCommand , DeleteChannelCommand , DeleteEmojiCommand , DeleteMessageCommand ,
19+ DeleteRoleCommand , DeleteScheduledEventCommand , DeleteWebhookCommand , EditChannelCommand ,
20+ EditMessageCommand , ExecuteWebhookCommand , FetchMemberCommand , FetchMessagesCommand ,
21+ GuildMemberNickCommand , InteractionDeferCommand , InteractionFollowupCommand ,
22+ InteractionRespondCommand , KickUserCommand , ModalRespondCommand , PinMessageCommand ,
23+ RemoveReactionCommand , RemoveRoleCommand , RevokeInviteCommand , SendMessageCommand ,
24+ SetBotPresenceCommand , TimeoutUserCommand , TypingCommand , UnbanUserCommand ,
2325 UnpinMessageCommand , VoiceDisconnectCommand , VoiceMoveCommand ,
2426} ;
2527use discord_types:: types:: {
@@ -338,6 +340,7 @@ impl OutboundProcessor {
338340 r11, r12, r13, r14, r15, r16, r17, r18, r19, r20,
339341 r21, r22, r23, r24, r25, r26, r27, r28, r29, r30,
340342 r31, r32, r33, r34, r35, r36, r37,
343+ r38, r39, r40, r41, r42, r43,
341344 ) = tokio:: join!(
342345 Self :: handle_send_messages(
343346 http. clone( ) ,
@@ -411,6 +414,12 @@ impl OutboundProcessor {
411414 Self :: handle_webhook_delete( http. clone( ) , client. clone( ) , prefix. clone( ) ) ,
412415 Self :: handle_voice_move( http. clone( ) , client. clone( ) , prefix. clone( ) , publisher. clone( ) ) ,
413416 Self :: handle_voice_disconnect( http. clone( ) , client. clone( ) , prefix. clone( ) , publisher. clone( ) ) ,
417+ Self :: handle_invite_create( http. clone( ) , client. clone( ) , prefix. clone( ) ) ,
418+ Self :: handle_invite_revoke( http. clone( ) , client. clone( ) , prefix. clone( ) ) ,
419+ Self :: handle_emoji_create( http. clone( ) , client. clone( ) , prefix. clone( ) ) ,
420+ Self :: handle_emoji_delete( http. clone( ) , client. clone( ) , prefix. clone( ) ) ,
421+ Self :: handle_scheduled_event_create( http. clone( ) , client. clone( ) , prefix. clone( ) ) ,
422+ Self :: handle_scheduled_event_delete( http. clone( ) , client. clone( ) , prefix. clone( ) ) ,
414423 ) ;
415424
416425 // Log any errors (all handlers run indefinitely until NATS disconnects)
@@ -452,6 +461,12 @@ impl OutboundProcessor {
452461 ( "webhook_delete" , r35) ,
453462 ( "voice_move" , r36) ,
454463 ( "voice_disconnect" , r37) ,
464+ ( "invite_create" , r38) ,
465+ ( "invite_revoke" , r39) ,
466+ ( "emoji_create" , r40) ,
467+ ( "emoji_delete" , r41) ,
468+ ( "scheduled_event_create" , r42) ,
469+ ( "scheduled_event_delete" , r43) ,
455470 ] {
456471 if let Err ( e) = result {
457472 error ! ( "Outbound handler '{}' exited with error: {}" , name, e) ;
@@ -2263,6 +2278,182 @@ impl OutboundProcessor {
22632278 }
22642279 Ok ( ( ) )
22652280 }
2281+
2282+ async fn handle_invite_create (
2283+ http : Arc < Http > ,
2284+ client : async_nats:: Client ,
2285+ prefix : String ,
2286+ ) -> Result < ( ) > {
2287+ let subscriber = MessageSubscriber :: new ( client, & prefix) ;
2288+ let subject = subjects:: agent:: invite_create ( & prefix) ;
2289+ let mut stream = subscriber. subscribe :: < CreateInviteCommand > ( & subject) . await ?;
2290+ info ! ( "Listening for invite_create commands on {}" , subject) ;
2291+ while let Some ( result) = stream. next ( ) . await {
2292+ match result {
2293+ Ok ( cmd) => {
2294+ let channel = ChannelId :: new ( cmd. channel_id ) ;
2295+ let builder = serenity:: builder:: CreateInvite :: new ( )
2296+ . max_age ( cmd. max_age_secs as u32 )
2297+ . max_uses ( cmd. max_uses as u8 )
2298+ . temporary ( cmd. temporary )
2299+ . unique ( cmd. unique ) ;
2300+ if let Err ( e) = channel. create_invite ( & * http, builder) . await {
2301+ warn ! ( "Failed to create invite for channel {}: {}" , cmd. channel_id, e) ;
2302+ }
2303+ }
2304+ Err ( e) => warn ! ( "Failed to deserialize invite_create command: {}" , e) ,
2305+ }
2306+ }
2307+ Ok ( ( ) )
2308+ }
2309+
2310+ async fn handle_invite_revoke (
2311+ http : Arc < Http > ,
2312+ client : async_nats:: Client ,
2313+ prefix : String ,
2314+ ) -> Result < ( ) > {
2315+ let subscriber = MessageSubscriber :: new ( client, & prefix) ;
2316+ let subject = subjects:: agent:: invite_revoke ( & prefix) ;
2317+ let mut stream = subscriber. subscribe :: < RevokeInviteCommand > ( & subject) . await ?;
2318+ info ! ( "Listening for invite_revoke commands on {}" , subject) ;
2319+ while let Some ( result) = stream. next ( ) . await {
2320+ match result {
2321+ Ok ( cmd) => {
2322+ let reason = cmd. reason . as_deref ( ) ;
2323+ if let Err ( e) = http. delete_invite ( & cmd. code , reason) . await {
2324+ warn ! ( "Failed to revoke invite {}: {}" , cmd. code, e) ;
2325+ }
2326+ }
2327+ Err ( e) => warn ! ( "Failed to deserialize invite_revoke command: {}" , e) ,
2328+ }
2329+ }
2330+ Ok ( ( ) )
2331+ }
2332+
2333+ async fn handle_emoji_create (
2334+ http : Arc < Http > ,
2335+ client : async_nats:: Client ,
2336+ prefix : String ,
2337+ ) -> Result < ( ) > {
2338+ let subscriber = MessageSubscriber :: new ( client, & prefix) ;
2339+ let subject = subjects:: agent:: emoji_create ( & prefix) ;
2340+ let mut stream = subscriber. subscribe :: < CreateEmojiCommand > ( & subject) . await ?;
2341+ info ! ( "Listening for emoji_create commands on {}" , subject) ;
2342+ while let Some ( result) = stream. next ( ) . await {
2343+ match result {
2344+ Ok ( cmd) => {
2345+ let guild = GuildId :: new ( cmd. guild_id ) ;
2346+ if let Err ( e) = guild. create_emoji ( & * http, & cmd. name , & cmd. image_data ) . await {
2347+ warn ! ( "Failed to create emoji '{}' in guild {}: {}" , cmd. name, cmd. guild_id, e) ;
2348+ }
2349+ }
2350+ Err ( e) => warn ! ( "Failed to deserialize emoji_create command: {}" , e) ,
2351+ }
2352+ }
2353+ Ok ( ( ) )
2354+ }
2355+
2356+ async fn handle_emoji_delete (
2357+ http : Arc < Http > ,
2358+ client : async_nats:: Client ,
2359+ prefix : String ,
2360+ ) -> Result < ( ) > {
2361+ let subscriber = MessageSubscriber :: new ( client, & prefix) ;
2362+ let subject = subjects:: agent:: emoji_delete ( & prefix) ;
2363+ let mut stream = subscriber. subscribe :: < DeleteEmojiCommand > ( & subject) . await ?;
2364+ info ! ( "Listening for emoji_delete commands on {}" , subject) ;
2365+ while let Some ( result) = stream. next ( ) . await {
2366+ match result {
2367+ Ok ( cmd) => {
2368+ let guild = GuildId :: new ( cmd. guild_id ) ;
2369+ let emoji_id = serenity:: model:: id:: EmojiId :: new ( cmd. emoji_id ) ;
2370+ if let Err ( e) = guild. delete_emoji ( & * http, emoji_id) . await {
2371+ warn ! ( "Failed to delete emoji {} from guild {}: {}" , cmd. emoji_id, cmd. guild_id, e) ;
2372+ }
2373+ }
2374+ Err ( e) => warn ! ( "Failed to deserialize emoji_delete command: {}" , e) ,
2375+ }
2376+ }
2377+ Ok ( ( ) )
2378+ }
2379+
2380+ async fn handle_scheduled_event_create (
2381+ http : Arc < Http > ,
2382+ client : async_nats:: Client ,
2383+ prefix : String ,
2384+ ) -> Result < ( ) > {
2385+ use serenity:: builder:: CreateScheduledEvent ;
2386+ use serenity:: model:: guild:: ScheduledEventType ;
2387+
2388+ let subscriber = MessageSubscriber :: new ( client, & prefix) ;
2389+ let subject = subjects:: agent:: scheduled_event_create ( & prefix) ;
2390+ let mut stream = subscriber. subscribe :: < CreateScheduledEventCommand > ( & subject) . await ?;
2391+ info ! ( "Listening for scheduled_event_create commands on {}" , subject) ;
2392+ while let Some ( result) = stream. next ( ) . await {
2393+ match result {
2394+ Ok ( cmd) => {
2395+ let guild = GuildId :: new ( cmd. guild_id ) ;
2396+ let start = match cmd. start_time . parse :: < serenity:: model:: Timestamp > ( ) {
2397+ Ok ( t) => t,
2398+ Err ( e) => {
2399+ warn ! ( "Invalid start_time '{}': {}" , cmd. start_time, e) ;
2400+ continue ;
2401+ }
2402+ } ;
2403+
2404+ let ( kind, mut builder) = if let Some ( channel_id) = cmd. channel_id {
2405+ let b = CreateScheduledEvent :: new ( ScheduledEventType :: Voice , & cmd. name , start)
2406+ . channel_id ( ChannelId :: new ( channel_id) ) ;
2407+ ( ScheduledEventType :: Voice , b)
2408+ } else {
2409+ let location = cmd. external_location . unwrap_or_default ( ) ;
2410+ let end = cmd. end_time . as_deref ( )
2411+ . and_then ( |s| s. parse :: < serenity:: model:: Timestamp > ( ) . ok ( ) ) ;
2412+ let mut b = CreateScheduledEvent :: new ( ScheduledEventType :: External , & cmd. name , start)
2413+ . location ( & location) ;
2414+ if let Some ( end_ts) = end {
2415+ b = b. end_time ( end_ts) ;
2416+ }
2417+ ( ScheduledEventType :: External , b)
2418+ } ;
2419+ let _ = kind;
2420+ if let Some ( ref desc) = cmd. description {
2421+ builder = builder. description ( desc) ;
2422+ }
2423+
2424+ if let Err ( e) = guild. create_scheduled_event ( & * http, builder) . await {
2425+ warn ! ( "Failed to create scheduled event '{}' in guild {}: {}" , cmd. name, cmd. guild_id, e) ;
2426+ }
2427+ }
2428+ Err ( e) => warn ! ( "Failed to deserialize scheduled_event_create command: {}" , e) ,
2429+ }
2430+ }
2431+ Ok ( ( ) )
2432+ }
2433+
2434+ async fn handle_scheduled_event_delete (
2435+ http : Arc < Http > ,
2436+ client : async_nats:: Client ,
2437+ prefix : String ,
2438+ ) -> Result < ( ) > {
2439+ let subscriber = MessageSubscriber :: new ( client, & prefix) ;
2440+ let subject = subjects:: agent:: scheduled_event_delete ( & prefix) ;
2441+ let mut stream = subscriber. subscribe :: < DeleteScheduledEventCommand > ( & subject) . await ?;
2442+ info ! ( "Listening for scheduled_event_delete commands on {}" , subject) ;
2443+ while let Some ( result) = stream. next ( ) . await {
2444+ match result {
2445+ Ok ( cmd) => {
2446+ let guild = GuildId :: new ( cmd. guild_id ) ;
2447+ let event_id = serenity:: model:: id:: ScheduledEventId :: new ( cmd. event_id ) ;
2448+ if let Err ( e) = guild. delete_scheduled_event ( & * http, event_id) . await {
2449+ warn ! ( "Failed to delete scheduled event {} from guild {}: {}" , cmd. event_id, cmd. guild_id, e) ;
2450+ }
2451+ }
2452+ Err ( e) => warn ! ( "Failed to deserialize scheduled_event_delete command: {}" , e) ,
2453+ }
2454+ }
2455+ Ok ( ( ) )
2456+ }
22662457}
22672458
22682459/// Publish a `CommandErrorEvent` to NATS if the outcome is `Permanent`.
0 commit comments