作者 邓超

优化 同步

@@ -733,7 +733,7 @@ class Imap { @@ -733,7 +733,7 @@ class Imap {
733 }elseif($header2Body=='body'){ 733 }elseif($header2Body=='body'){
734 $filed = 'RFC822.TEXT'; 734 $filed = 'RFC822.TEXT';
735 }else{ 735 }else{
736 - $filed = 'UID FLAGS INTERNALDATE'; 736 + $filed = $header2Body;
737 } 737 }
738 738
739 // 读取数据 739 // 读取数据
@@ -194,153 +194,139 @@ class Mail { @@ -194,153 +194,139 @@ class Mail {
194 false 194 false
195 ); 195 );
196 196
197 -  
198 - // 最后拉取的msgno  
199 - $lastMsgno = $db->value(listsSql::lastMsgno($email_id,$folder_id));  
200 -  
201 - $nu = 20;  
202 -  
203 - if(!$lastMsgno){  
204 - $msgno = range(1,$nu);  
205 - }else{  
206 - $msgno = range($lastMsgno,$lastMsgno+$nu);  
207 -  
208 - if($lastMsgno > $status['EXISTS']){  
209 - $msgno = range($status['EXISTS'] > $nu ? $status['EXISTS'] - $nu : 1,$status['EXISTS']);  
210 - }  
211 - // 一样就不拉新的  
212 - if($lastMsgno == $status['EXISTS']){  
213 - return true;  
214 - } 197 + if(!$status['EXISTS']){
  198 + return true;
215 } 199 }
216 200
  201 + //
  202 + $nu = 100;
  203 + $msgno = 1;
  204 + while (true){
  205 + // 是否结束了
  206 + if($status['EXISTS'] < $msgno){
  207 + break;
  208 + }
217 209
218 - // 循环  
219 - $results = $this->client->fetchHeader($msgno);  
220 - if($results && is_array($results)){  
221 - // 表示已存在新邮件  
222 - if($folder == 'INBOX') redis()->incr('have_new_mail_'.$email_id,120);  
223 -  
224 - // 批量插入  
225 - foreach ($results as $key=>$result){  
226 - $header = $result['HEADER.FIELDS'];  
227 -  
228 - foreach ($result['FLAGS'] as $k=>$FLAG){  
229 - $result['FLAGS'][$k] = strtolower(str_replace('\\','',$FLAG));  
230 - }  
231 - try {  
232 - 210 + $uids = $this->client->fetch(range($msgno,($msgno-1)+$nu),'UID');
  211 + if(!$uids){
  212 + break;
  213 + }
233 214
234 -// if(empty($header['Subject'])){  
235 -// logs($result);  
236 -// } 215 + $uids = array_column($uids,'UID');
  216 + $existsUids = $db->value(listsSql::getUids($email_id,$folder_id,$uids));
  217 + // 获取不存在数据库的uid
  218 + $uids = array_diff($uids,$existsUids);
  219 +
  220 + $msgno += $nu;
  221 +
  222 + // 开始同步
  223 + if($uids){
  224 + $results = $this->client->fetchHeader($uids,true);
  225 +
  226 + if($results && is_array($results)){
  227 + // 表示已存在新邮件
  228 + if($folder == 'INBOX') redis()->incr('have_new_mail_'.$email_id,120);
  229 +
  230 + // 批量插入
  231 + foreach ($results as $key=>$result){
  232 + $header = $result['HEADER.FIELDS'];
  233 +
  234 + foreach ($result['FLAGS'] as $k=>$FLAG){
  235 + $result['FLAGS'][$k] = strtolower(str_replace('\\','',$FLAG));
  236 + }
  237 + try {
  238 +
  239 + // 没有收件人
  240 + if(!empty($header['To'])){
  241 + $header['To'] = MailFun::toOrFrom($header['To']);
  242 + }else{
  243 + $header['To'] = [];
  244 + }
  245 +
  246 + $header['From'] = MailFun::toOrFrom($header['From']);
  247 + // 抄送 ,密送
  248 + $cc = [];
  249 + $bcc = [];
  250 + if($header['Cc']??''){
  251 + $cc = MailFun::toOrFrom($header['Cc']);
  252 + }
  253 + if($header['Bcc']??''){
  254 + $bcc = MailFun::toOrFrom($header['Bcc']);
  255 + }
  256 +
  257 +
  258 + $data = [
  259 + 'msgno' => $key,
  260 + 'uid' => $result['UID'],
  261 + 'subject' => $header['Subject']??'',
  262 + 'cc' => $cc,
  263 + 'bcc' => $bcc,
  264 + 'from' => $header['From'][0]['email']??'',
  265 + 'from_name' => $header['From'][0]['name']??'',
  266 + 'to' => $header['To']?implode(',',array_column($header['To'],'email')):'',
  267 + 'to_name' => json_encode($header['To']),
  268 + 'date' => strtotime(is_array($header['Date']??'') ? $header['Date'][0] : $header['Date']??''),
  269 + 'message_id' => $header['Message-ID']??'',
  270 + 'udate' => strtotime($result['INTERNALDATE']),
  271 + 'size' => $result['RFC822.SIZE']??0,
  272 + 'recent' => in_array('recent',$result['FLAGS']) ? 1 : 0,
  273 + 'seen' => in_array('seen',$result['FLAGS']) ? 1 : 0,
  274 + 'draft' => in_array('draft',$result['FLAGS']) ? 1 : 0,
  275 + 'flagged' => in_array('flagged',$result['FLAGS']) ? 1 : 0,
  276 + 'answered' => in_array('answered',$result['FLAGS']) ? 1 : 0,
  277 + 'folder_id' => $folder_id,
  278 + 'email_id' => $email_id,
  279 + 'uuid' => md5($email_id.$folder_id.$result['UID']),
  280 + 'is_file' => MailFun::isFile($result['BODYSTRUCTURE']??'') ? 1: 0 //是否附件
  281 + ];
  282 + $data['date'] = $data['date'] ? : 0;
  283 + }catch (\Throwable $e){
  284 + logs(
  285 + '邮件解析失败:'.PHP_EOL.$e->getMessage().PHP_EOL.print_r($result,true),
  286 + LOG_PATH.'/imap/mail/'.$email_id.'/'.$result['UID'].'.log'
  287 + );
  288 + unset($results[$key]);
  289 + continue;
  290 + }
  291 +
  292 + // 插入数据库
  293 + try {
  294 + $id = $db->insert(listsSql::$table,$data);
  295 + if($id){
  296 + // 同步body内容
  297 + redis()->rPush('sync_email_body', [
  298 + 'lists_id' => $id,
  299 + 'email_id' => $email_id,
  300 + 'folder_id' => $folder_id,
  301 + 'folder' => $folder,
  302 + 'uid' => $data['uid'],
  303 + ]);
  304 + }
  305 + }catch (\Throwable $e){
  306 +
  307 + }
237 308
238 - // 没有收件人  
239 - if(!empty($header['To'])){  
240 - $header['To'] = MailFun::toOrFrom($header['To']);  
241 - }else{  
242 - $header['To'] = [];  
243 } 309 }
244 310
245 - $header['From'] = MailFun::toOrFrom($header['From']);  
246 - // 抄送 ,密送  
247 - $cc = [];  
248 - $bcc = [];  
249 - if($header['Cc']??''){  
250 - $cc = MailFun::toOrFrom($header['Cc']); 311 + // 结束操作了
  312 + if(redis()->get(SYNC_RUNNING_REDIS_KEY) == 'stop'){
  313 + break;
251 } 314 }
252 - if($header['Bcc']??''){  
253 - $bcc = MailFun::toOrFrom($header['Bcc']);  
254 - }  
255 -  
256 315
257 - $data = [  
258 - 'msgno' => $key,  
259 - 'uid' => $result['UID'],  
260 - 'subject' => $header['Subject']??'',  
261 - 'cc' => $cc,  
262 - 'bcc' => $bcc,  
263 - 'from' => $header['From'][0]['email']??'',  
264 - 'from_name' => $header['From'][0]['name']??'',  
265 - 'to' => $header['To']?implode(',',array_column($header['To'],'email')):'',  
266 - 'to_name' => json_encode($header['To']),  
267 - 'date' => strtotime(is_array($header['Date']??'') ? $header['Date'][0] : $header['Date']??''),  
268 - 'message_id' => $header['Message-ID']??'',  
269 - 'udate' => strtotime($result['INTERNALDATE']),  
270 - 'size' => $result['RFC822.SIZE']??0,  
271 - 'recent' => in_array('recent',$result['FLAGS']) ? 1 : 0,  
272 - 'seen' => in_array('seen',$result['FLAGS']) ? 1 : 0,  
273 - 'draft' => in_array('draft',$result['FLAGS']) ? 1 : 0,  
274 - 'flagged' => in_array('flagged',$result['FLAGS']) ? 1 : 0,  
275 - 'answered' => in_array('answered',$result['FLAGS']) ? 1 : 0,  
276 - 'folder_id' => $folder_id,  
277 - 'email_id' => $email_id,  
278 - 'uuid' => md5($email_id.$folder_id.$result['UID']),  
279 - 'is_file' => MailFun::isFile($result['BODYSTRUCTURE']??'') ? 1: 0 //是否附件  
280 - ];  
281 - $data['date'] = $data['date'] ? : 0;  
282 - }catch (\Throwable $e){  
283 - logs(  
284 - '邮件解析失败:'.PHP_EOL.$e->getMessage().PHP_EOL.print_r($result,true),  
285 - LOG_PATH.'/imap/mail/'.$email_id.'/'.$result['UID'].'.log'  
286 - );  
287 - unset($results[$key]);  
288 - continue;  
289 } 316 }
290 317
291 - $results[$key] = $data;  
292 - }  
293 -  
294 - // 保存数据,这里其实不用再次写循环的。我想写一个  
295 - $uuids = $db->all(listsSql::hasUuid(array_column($results,'uuid')));  
296 - $uuids = $uuids ? array_column($uuids,null,'uuid') : [];  
297 -  
298 -// $db->transaction();  
299 - foreach ($results as $insert){  
300 - if(empty($uuids[$insert['uuid']])){  
301 - // 新增  
302 - try {  
303 - $id = $db->insert(listsSql::$table,$insert);  
304 - // 同步body内容  
305 - redis()->rPush('sync_email_body', [  
306 - 'lists_id' => $id,  
307 - 'email_id' => $email_id,  
308 - 'folder_id' => $folder_id,  
309 - 'folder' => $folder,  
310 - 'uid' => $insert['uid'],  
311 - ]);  
312 - }catch (\Throwable $e){  
313 -  
314 - }  
315 -  
316 -  
317 - }else{  
318 - // 修改  
319 - $db->update(  
320 - listsSql::$table,  
321 - $insert,  
322 - dbWhere(['id'=>$uuids[$insert['uuid']]['id']])  
323 - );  
324 - }  
325 - }  
326 -// $db->commit();  
327 -  
328 - // 更新数量  
329 - $db->update(  
330 - folderSql::$table,  
331 - ['last_sync_time' => time()],  
332 - dbWhere(['id'=>$folder_id]),  
333 - false  
334 - );  
335 - // 结束操作了  
336 -  
337 - if(redis()->get(SYNC_RUNNING_REDIS_KEY) != 'stop'){  
338 - // 再次调用  
339 - $this->syncMail($email_id,$folder_id,$folder,$db);  
340 } 318 }
341 319
342 } 320 }
343 321
  322 + // 更新数量
  323 + $db->update(
  324 + folderSql::$table,
  325 + ['last_sync_time' => time()],
  326 + dbWhere(['id'=>$folder_id]),
  327 + false
  328 + );
  329 +
344 return true; 330 return true;
345 331
346 } 332 }
@@ -60,6 +60,19 @@ class listsSql { @@ -60,6 +60,19 @@ class listsSql {
60 } 60 }
61 61
62 /** 62 /**
  63 + * 获取已有的uid
  64 + * @param int $email_id
  65 + * @param int $folder_id
  66 + * @param array $uids
  67 + * @return string
  68 + * @author:dc
  69 + * @time 2023/4/23 16:54
  70 + */
  71 + public static function getUids(int $email_id, int $folder_id, array $uids){
  72 + return "select `uid` from `".static::$table."` where ".dbWhere(['email_id'=>$email_id,'folder_id'=>$folder_id,'uid'=>$uids]);
  73 + }
  74 +
  75 + /**
63 * 获取已存在的id 76 * 获取已存在的id
64 * @param $email_id 77 * @param $email_id
65 * @param $folder_id 78 * @param $folder_id