mirror of
				https://github.com/stalwartlabs/mail-server.git
				synced 2025-10-31 14:56:16 +08:00 
			
		
		
		
	Group pipelined IMAP FETCH and STATUS operations
This commit is contained in:
		
							parent
							
								
									4c7052d227
								
							
						
					
					
						commit
						54733de0ff
					
				
					 3 changed files with 93 additions and 62 deletions
				
			
		|  | @ -111,7 +111,7 @@ impl<T: SessionStream> Session<T> { | |||
|                     .await | ||||
|                     .map(|_| SessionResult::Continue), | ||||
|                 Command::Status => self | ||||
|                     .handle_status(request) | ||||
|                     .handle_status(group_requests(&mut requests, vec![request])) | ||||
|                     .await | ||||
|                     .map(|_| SessionResult::Continue), | ||||
|                 Command::Append => self | ||||
|  | @ -134,8 +134,8 @@ impl<T: SessionStream> Session<T> { | |||
|                     .handle_search(request, false, is_uid) | ||||
|                     .await | ||||
|                     .map(|_| SessionResult::Continue), | ||||
|                 Command::Fetch(is_uid) => self | ||||
|                     .handle_fetch(request, is_uid) | ||||
|                 Command::Fetch(_) => self | ||||
|                     .handle_fetch(group_requests(&mut requests, vec![request])) | ||||
|                     .await | ||||
|                     .map(|_| SessionResult::Continue), | ||||
|                 Command::Store(is_uid) => self | ||||
|  |  | |||
|  | @ -42,22 +42,22 @@ use trc::AddContext; | |||
| use super::{FromModSeq, ImapContext}; | ||||
| 
 | ||||
| impl<T: SessionStream> Session<T> { | ||||
|     pub async fn handle_fetch( | ||||
|         &mut self, | ||||
|         request: Request<Command>, | ||||
|         is_uid: bool, | ||||
|     ) -> trc::Result<()> { | ||||
|     pub async fn handle_fetch(&mut self, requests: Vec<Request<Command>>) -> trc::Result<()> { | ||||
|         // Validate access
 | ||||
|         self.assert_has_permission(Permission::ImapFetch)?; | ||||
| 
 | ||||
|         let op_start = Instant::now(); | ||||
|         let arguments = request.parse_fetch()?; | ||||
| 
 | ||||
|         let (data, mailbox) = self.state.select_data(); | ||||
|         let is_qresync = self.is_qresync; | ||||
|         let is_rev2 = self.version.is_rev2(); | ||||
| 
 | ||||
|         let enabled_condstore = if !self.is_condstore && arguments.changed_since.is_some() | ||||
|         let mut ops = Vec::with_capacity(requests.len()); | ||||
| 
 | ||||
|         for request in requests { | ||||
|             let is_uid = matches!(request.command, Command::Fetch(true)); | ||||
|             match request.parse_fetch() { | ||||
|                 Ok(arguments) => { | ||||
|                     let enabled_condstore = if !self.is_condstore | ||||
|                         && arguments.changed_since.is_some() | ||||
|                         || arguments.attributes.contains(&Attribute::ModSeq) | ||||
|                     { | ||||
|                         self.is_condstore = true; | ||||
|  | @ -66,19 +66,37 @@ impl<T: SessionStream> Session<T> { | |||
|                         false | ||||
|                     }; | ||||
| 
 | ||||
|                     ops.push(Ok((is_uid, enabled_condstore, arguments))); | ||||
|                 } | ||||
|                 Err(err) => { | ||||
|                     ops.push(Err(err)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         spawn_op!(data, { | ||||
|             for op in ops { | ||||
|                 match op { | ||||
|                     Ok((is_uid, enabled_condstore, arguments)) => { | ||||
|                         let response = data | ||||
|                             .fetch( | ||||
|                                 arguments, | ||||
|                     mailbox, | ||||
|                                 mailbox.clone(), | ||||
|                                 is_uid, | ||||
|                                 is_qresync, | ||||
|                                 is_rev2, | ||||
|                                 enabled_condstore, | ||||
|                     op_start, | ||||
|                                 Instant::now(), | ||||
|                             ) | ||||
|                             .await?; | ||||
|             data.write_bytes(response.into_bytes()).await | ||||
| 
 | ||||
|                         data.write_bytes(response.into_bytes()).await?; | ||||
|                     } | ||||
|                     Err(err) => data.write_error(err).await?, | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -34,20 +34,27 @@ use trc::AddContext; | |||
| use super::ToModSeq; | ||||
| 
 | ||||
| impl<T: SessionStream> Session<T> { | ||||
|     pub async fn handle_status(&mut self, request: Request<Command>) -> trc::Result<()> { | ||||
|     pub async fn handle_status(&mut self, requests: Vec<Request<Command>>) -> trc::Result<()> { | ||||
|         // Validate access
 | ||||
|         self.assert_has_permission(Permission::ImapStatus)?; | ||||
| 
 | ||||
|         let op_start = Instant::now(); | ||||
|         let arguments = request.parse_status(self.version)?; | ||||
|         let version = self.version; | ||||
|         let data = self.state.session_data(); | ||||
| 
 | ||||
|         spawn_op!(data, { | ||||
|             let mut did_sync = false; | ||||
| 
 | ||||
|             for request in requests.into_iter() { | ||||
|                 match request.parse_status(version) { | ||||
|                     Ok(arguments) => { | ||||
|                         let op_start = Instant::now(); | ||||
|                         if !did_sync { | ||||
|                             // Refresh mailboxes
 | ||||
|                             data.synchronize_mailboxes(false) | ||||
|                                 .await | ||||
|                                 .imap_ctx(&arguments.tag, trc::location!())?; | ||||
|                             did_sync = true; | ||||
|                         } | ||||
| 
 | ||||
|                         // Fetch status
 | ||||
|                         let status = data | ||||
|  | @ -74,7 +81,13 @@ impl<T: SessionStream> Session<T> { | |||
|                                 .with_tag(arguments.tag) | ||||
|                                 .serialize(buf), | ||||
|                         ) | ||||
|             .await | ||||
|                         .await?; | ||||
|                     } | ||||
|                     Err(err) => data.write_error(err).await?, | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue