@@ -57,15 +57,27 @@ pub async fn to_zulip_id(client: &GithubClient, github_id: i64) -> anyhow::Resul
5757 . map ( |v| * v. 0 ) )
5858}
5959
60+ /// Top-level handler for Zulip webhooks.
61+ ///
62+ /// Returns a JSON response.
6063pub async fn respond ( ctx : & Context , req : Request ) -> String {
6164 let content = match process_zulip_request ( ctx, req) . await {
62- Ok ( s) => s,
65+ Ok ( None ) => {
66+ return serde_json:: to_string ( & ResponseNotRequired {
67+ response_not_required : true ,
68+ } )
69+ . unwrap ( ) ;
70+ }
71+ Ok ( Some ( s) ) => s,
6372 Err ( e) => format ! ( "{:?}" , e) ,
6473 } ;
6574 serde_json:: to_string ( & Response { content } ) . unwrap ( )
6675}
6776
68- async fn process_zulip_request ( ctx : & Context , req : Request ) -> anyhow:: Result < String > {
77+ /// Processes a Zulip webhook.
78+ ///
79+ /// Returns a string of the response, or None if no response is needed.
80+ async fn process_zulip_request ( ctx : & Context , req : Request ) -> anyhow:: Result < Option < String > > {
6981 let expected_token = std:: env:: var ( "ZULIP_TOKEN" ) . expect ( "`ZULIP_TOKEN` set for authorization" ) ;
7082
7183 if !openssl:: memcmp:: eq ( req. token . as_bytes ( ) , expected_token. as_bytes ( ) ) {
@@ -91,7 +103,8 @@ fn handle_command<'a>(
91103 gh_id : anyhow:: Result < i64 > ,
92104 words : & ' a str ,
93105 message_data : & ' a Message ,
94- ) -> std:: pin:: Pin < Box < dyn std:: future:: Future < Output = anyhow:: Result < String > > + Send + ' a > > {
106+ ) -> std:: pin:: Pin < Box < dyn std:: future:: Future < Output = anyhow:: Result < Option < String > > > + Send + ' a > >
107+ {
95108 Box :: pin ( async move {
96109 log:: trace!( "handling zulip command {:?}" , words) ;
97110 let mut words = words. split_whitespace ( ) ;
@@ -152,7 +165,7 @@ fn handle_command<'a>(
152165 next = words. next ( ) ;
153166 }
154167
155- Ok ( String :: from ( "Unknown command" ) )
168+ Ok ( Some ( String :: from ( "Unknown command" ) ) )
156169 }
157170 }
158171 } )
@@ -166,7 +179,7 @@ async fn execute_for_other_user(
166179 ctx : & Context ,
167180 mut words : impl Iterator < Item = & str > ,
168181 message_data : & Message ,
169- ) -> anyhow:: Result < String > {
182+ ) -> anyhow:: Result < Option < String > > {
170183 // username is a GitHub username, not a Zulip username
171184 let username = match words. next ( ) {
172185 Some ( username) => username,
@@ -222,7 +235,9 @@ async fn execute_for_other_user(
222235 . find ( |m| m. user_id == zulip_user_id)
223236 . ok_or_else ( || format_err ! ( "Could not find Zulip user email." ) ) ?;
224237
225- let output = handle_command ( ctx, Ok ( user_id as i64 ) , & command, message_data) . await ?;
238+ let output = handle_command ( ctx, Ok ( user_id as i64 ) , & command, message_data)
239+ . await ?
240+ . unwrap_or_default ( ) ;
226241
227242 // At this point, the command has been run.
228243 let sender = match & message_data. sender_short_name {
@@ -255,7 +270,7 @@ async fn execute_for_other_user(
255270 }
256271 }
257272
258- Ok ( output)
273+ Ok ( Some ( output) )
259274}
260275
261276#[ derive( serde:: Deserialize ) ]
@@ -441,7 +456,7 @@ async fn acknowledge(
441456 ctx : & Context ,
442457 gh_id : i64 ,
443458 mut words : impl Iterator < Item = & str > ,
444- ) -> anyhow:: Result < String > {
459+ ) -> anyhow:: Result < Option < String > > {
445460 let filter = match words. next ( ) {
446461 Some ( filter) => {
447462 if words. next ( ) . is_some ( ) {
@@ -489,14 +504,14 @@ async fn acknowledge(
489504 resp
490505 } ;
491506
492- Ok ( resp)
507+ Ok ( Some ( resp) )
493508}
494509
495510async fn add_notification (
496511 ctx : & Context ,
497512 gh_id : i64 ,
498513 mut words : impl Iterator < Item = & str > ,
499- ) -> anyhow:: Result < String > {
514+ ) -> anyhow:: Result < Option < String > > {
500515 let url = match words. next ( ) {
501516 Some ( idx) => idx,
502517 None => anyhow:: bail!( "url not present" ) ,
@@ -525,7 +540,7 @@ async fn add_notification(
525540 )
526541 . await
527542 {
528- Ok ( ( ) ) => Ok ( "Created!" . to_string ( ) ) ,
543+ Ok ( ( ) ) => Ok ( Some ( "Created!" . to_string ( ) ) ) ,
529544 Err ( e) => Err ( format_err ! ( "Failed to create: {e:?}" ) ) ,
530545 }
531546}
@@ -534,7 +549,7 @@ async fn add_meta_notification(
534549 ctx : & Context ,
535550 gh_id : i64 ,
536551 mut words : impl Iterator < Item = & str > ,
537- ) -> anyhow:: Result < String > {
552+ ) -> anyhow:: Result < Option < String > > {
538553 let idx = match words. next ( ) {
539554 Some ( idx) => idx,
540555 None => anyhow:: bail!( "idx not present" ) ,
@@ -557,7 +572,7 @@ async fn add_meta_notification(
557572 } ;
558573 let mut db = ctx. db . get ( ) . await ;
559574 match add_metadata ( & mut db, gh_id, idx, description. as_deref ( ) ) . await {
560- Ok ( ( ) ) => Ok ( "Added metadata!" . to_string ( ) ) ,
575+ Ok ( ( ) ) => Ok ( Some ( "Added metadata!" . to_string ( ) ) ) ,
561576 Err ( e) => Err ( format_err ! ( "Failed to add: {e:?}" ) ) ,
562577 }
563578}
@@ -566,7 +581,7 @@ async fn move_notification(
566581 ctx : & Context ,
567582 gh_id : i64 ,
568583 mut words : impl Iterator < Item = & str > ,
569- ) -> anyhow:: Result < String > {
584+ ) -> anyhow:: Result < Option < String > > {
570585 let from = match words. next ( ) {
571586 Some ( idx) => idx,
572587 None => anyhow:: bail!( "from idx not present" ) ,
@@ -588,7 +603,7 @@ async fn move_notification(
588603 match move_indices ( & mut * ctx. db . get ( ) . await , gh_id, from, to) . await {
589604 Ok ( ( ) ) => {
590605 // to 1-base indices
591- Ok ( format ! ( "Moved {} to {}." , from + 1 , to + 1 ) )
606+ Ok ( Some ( format ! ( "Moved {} to {}." , from + 1 , to + 1 ) ) )
592607 }
593608 Err ( e) => Err ( format_err ! ( "Failed to move: {e:?}." ) ) ,
594609 }
@@ -662,7 +677,7 @@ async fn post_waiter(
662677 ctx : & Context ,
663678 message : & Message ,
664679 waiting : WaitingMessage < ' _ > ,
665- ) -> anyhow:: Result < String > {
680+ ) -> anyhow:: Result < Option < String > > {
666681 let posted = MessageApiRequest {
667682 recipient : Recipient :: Stream {
668683 id : message
@@ -692,16 +707,13 @@ async fn post_waiter(
692707 . context ( "emoji reaction failed" ) ?;
693708 }
694709
695- Ok ( serde_json:: to_string ( & ResponseNotRequired {
696- response_not_required : true ,
697- } )
698- . unwrap ( ) )
710+ Ok ( None )
699711}
700712
701- async fn trigger_docs_update ( ) -> anyhow:: Result < String > {
713+ async fn trigger_docs_update ( ) -> anyhow:: Result < Option < String > > {
702714 match docs_update ( ) . await {
703- Ok ( None ) => Ok ( "No updates found." . to_string ( ) ) ,
704- Ok ( Some ( pr) ) => Ok ( format ! ( "Created docs update PR <{}>" , pr. html_url) ) ,
715+ Ok ( None ) => Ok ( Some ( "No updates found." . to_string ( ) ) ) ,
716+ Ok ( Some ( pr) ) => Ok ( Some ( format ! ( "Created docs update PR <{}>" , pr. html_url) ) ) ,
705717 Err ( e) => {
706718 // Don't send errors to Zulip since they may contain sensitive data.
707719 log:: error!( "Docs update via Zulip failed: {e:?}" ) ;
0 commit comments