作者 邓超

1

  1 +<?php
  2 +
  3 +//error_reporting();
  4 +
  5 +use Swoole\Process;
  6 +
  7 +
  8 +
  9 +include_once __DIR__."/../vendor/autoload.php";
  10 +
  11 +
  12 +function start(){
  13 +
  14 +// 删除停止运行的值
  15 + redis()->delete(RUNNING_REDIS_KEY);
  16 +
  17 + // 进程管理器
  18 + $pm = new Process\Manager();
  19 +
  20 + // 启动一个进程来管理定时
  21 + $pm->add(function (Process\Pool $pool, int $workerId){
  22 + _echo("定时进程({$workerId})启动成功");
  23 +
  24 +
  25 + // 进行阻塞,否则定时器无法运行
  26 + while (true){
  27 + co::sleep(9999);
  28 + }
  29 + },true);
  30 +
  31 +
  32 +// 协程配置
  33 + \co::set([
  34 + 'max_coroutine'=>COROUTINE_MAX_NUM, // 最大携程数量
  35 + 'hook_flags'=>SWOOLE_HOOK_TCP, // redis需要的配置
  36 + ]);
  37 +
  38 + // 启动业务进程
  39 + $pm->addBatch(WORKER_NUM,function (Process\Pool $pool, int $worker_id){
  40 + _echo("业务进程({$worker_id})启动成功");
  41 +
  42 + $start_num = 0;// 启动的协程数量
  43 +
  44 + // 循环阻塞
  45 + while (true){
  46 + // 是否到了协程配置的数量上限
  47 + if($start_num < COROUTINE_MAX_NUM){
  48 + // 需要同步的id
  49 + $id = redis()->lPop('sync_email_lists');
  50 +
  51 + if(!$id){
  52 + co::sleep(1);
  53 + }else{
  54 + // 启动一个协程
  55 + go(function () use (&$start_num,$worker_id,$id){
  56 + $start_num++;
  57 +
  58 + // 开始同步
  59 + try {
  60 + sync($id,$worker_id);
  61 + }catch (\Throwable $e){
  62 + // 重新发布同步任务,如果失败了是否重新发布
  63 + redis()->rPush('sync_email_lists',$id);
  64 +
  65 +// _echo($e->getMessage());
  66 + logs(
  67 + $e->getMessage().PHP_EOL.$e->getTraceAsString(),
  68 + LOG_PATH.'/'.$worker_id.'_'.co::getCid().'.log'
  69 + );
  70 + }
  71 +
  72 + // 协程完成后执行的函数
  73 + co::defer(function () use (&$start_num,$worker_id){
  74 +// _echo('正常关闭进程('.$worker_id.')下的协程('.co::getCid().')');
  75 + $start_num--;
  76 + });
  77 +
  78 + });
  79 +
  80 + }
  81 + }else{
  82 + // 协程到了最大的数量,阻塞1秒
  83 + co::sleep(1);
  84 + }
  85 +
  86 +
  87 + }
  88 +
  89 +
  90 + },true);
  91 +
  92 +
  93 + // 启动管理器
  94 + $pm->start();
  95 +
  96 +}
  97 +
  98 +
  99 +/**
  100 + * 开始同步, 这里是主要的业务代码
  101 + * @param $email_id
  102 + * @param $worker_id
  103 + * @return int
  104 + * @author:dc
  105 + * @time 2023/3/10 10:19
  106 + */
  107 +function sync($email_id,$worker_id){
  108 +
  109 + $email = db()->first(\Model\emailSql::first($email_id));
  110 + if(!$email){
  111 + return 0;
  112 + }
  113 +
  114 + if($email['pwd_error']){
  115 + return 1;
  116 + }
  117 +
  118 + $mailServer = new Lib\Mail\Mail();
  119 +
  120 + try {
  121 + // 登录服务器
  122 + $mailServer->login($email['email'],base64_decode($email['password']),$email['imap']);
  123 + }catch (Throwable $e){
  124 + if($e->getCode() == 403){
  125 + // 登录失败了 ,
  126 + db()->update(\Model\emailSql::$table,['pwd_error'=>1],dbWhere(['id'=>$email_id]));
  127 + }
  128 +
  129 + return 2;
  130 + }
  131 +
  132 + // 同步文件夹
  133 + $mailServer->syncFolder($email_id,db());
  134 +
  135 +
  136 + // 读取到邮箱中的文件夹
  137 + $folders = db()->all(\Model\folderSql::all($email['id']));
  138 + if(!$folders){
  139 + return 3;
  140 + }
  141 + $folders = list_to_tree($folders);
  142 + foreach ($folders as $folder){
  143 + try {
  144 + if(empty($folder['_child'])){
  145 + // 同步父文件夹
  146 + $mailServer->syncMail($email_id,$folder['id'],$folder['origin_folder']);
  147 + }else{
  148 + foreach ($folder as $item){
  149 + // 同步子文件夹
  150 + $mailServer->syncMail($email_id,$item['id'],$item['origin_folder']);
  151 + }
  152 + }
  153 +
  154 + }catch (Throwable $e){
  155 + logs(
  156 + $e->getMessage(),
  157 + LOG_PATH.'/imap/'.$email['email'].'.error.log'
  158 + );
  159 + }
  160 + }
  161 +
  162 +
  163 + $email = null;
  164 + $mailServer = null;
  165 +}
  166 +
  167 +
  168 +
  169 +
  170 +switch ($argv[1]){
  171 + case 'start':{
  172 + start();
  173 + break;
  174 + }
  175 + case 'stop':{
  176 + \Co\run(function (){
  177 + echo "正在退出程序...\n非必要请不要强制kill掉进程\n";
  178 + redis()->set(RUNNING_REDIS_KEY,'stop');
  179 + while (true){
  180 + $num = exec("ps -ef | grep \"sync.php start\" | grep -v grep | wc -l");
  181 + if(!$num){
  182 + break;
  183 + }
  184 + co::sleep(0.5);
  185 + }
  186 + echo "已退出程序\n";
  187 + });
  188 + break;
  189 + }
  190 + default:{
  191 + break;
  192 + }
  193 +}
  194 +
  195 +
  196 +
  197 +
  198 +
  199 +
  200 +
  201 +
  202 +
  203 +
1 <?php 1 <?php
2 2
  3 +/**
  4 + * TODO:: 这个文件是定时去拉取所有邮箱中的邮件
  5 + * 暂时不用这个
  6 + */
3 //error_reporting(); 7 //error_reporting();
4 8
5 use Swoole\Process; 9 use Swoole\Process;
@@ -3,9 +3,9 @@ @@ -3,9 +3,9 @@
3 error_reporting(E_ERROR | E_NOTICE); 3 error_reporting(E_ERROR | E_NOTICE);
4 4
5 // 开启4个进程 5 // 开启4个进程
6 -define('WORKER_NUM',2); 6 +define('WORKER_NUM',10);
7 // 开启最大1000个协程 7 // 开启最大1000个协程
8 -define('COROUTINE_MAX_NUM',1000); 8 +define('COROUTINE_MAX_NUM',5000);
9 // 是否继续运行 9 // 是否继续运行
10 define('RUNNING_REDIS_KEY','worker_is_running'); 10 define('RUNNING_REDIS_KEY','worker_is_running');
11 // 记录日志的目录 11 // 记录日志的目录
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 namespace Controller; 3 namespace Controller;
4 4
5 5
  6 +use Lib\Mail\Mail;
6 use Lib\Mail\MailFun; 7 use Lib\Mail\MailFun;
7 use Model\folderSql; 8 use Model\folderSql;
8 9
@@ -70,12 +71,41 @@ class Folder extends Base { @@ -70,12 +71,41 @@ class Folder extends Base {
70 ] 71 ]
71 )); 72 ));
72 73
  74 + if($has){
  75 + app()->e('folder_is_exist');
  76 + }
  77 +
  78 + // 远程创建
  79 + $mail = new Mail();
  80 + $mail->login($this->login_email['email'],$this->login_email['password'],$this->login_email['imap']);
  81 + $folder = $mail->client->folderCreate($formData['folder']);
  82 +
  83 +
  84 +
73 85
74 86
75 87
76 } 88 }
77 89
78 90
  91 + /**
  92 + * 改名
  93 + * @author:dc
  94 + * @time 2023/3/3 17:40
  95 + */
  96 + public function rename(){
  97 +
  98 + }
  99 +
  100 + /**
  101 + * 删除
  102 + * @author:dc
  103 + * @time 2023/3/3 17:38
  104 + */
  105 + public function delete(){
  106 +
  107 + }
  108 +
79 109
80 110
81 111
@@ -258,7 +258,7 @@ function list_to_tree($list, $pk='id',$pid = 'pid',$child = '_child',$root=0,$em @@ -258,7 +258,7 @@ function list_to_tree($list, $pk='id',$pid = 'pid',$child = '_child',$root=0,$em
258 * @author:dc 258 * @author:dc
259 * @time 2023/2/18 11:04 259 * @time 2023/2/18 11:04
260 */ 260 */
261 -function start_now_mail(){ 261 +function start_now_mail($email=null){
262 $id = 0; 262 $id = 0;
263 263
264 while (true){ 264 while (true){
@@ -23,5 +23,6 @@ return [ @@ -23,5 +23,6 @@ return [
23 'folder_create_name_error' => '文件夹名称只能输入中文英文数字', 23 'folder_create_name_error' => '文件夹名称只能输入中文英文数字',
24 'folder_parent_not_fount' => '上级文件夹不存在', 24 'folder_parent_not_fount' => '上级文件夹不存在',
25 'folder_tree_max_two' => '文件夹最多2级', 25 'folder_tree_max_two' => '文件夹最多2级',
  26 + 'folder_is_exist' => '文件夹已存在',
26 27
27 ]; 28 ];
@@ -430,12 +430,12 @@ class Imap { @@ -430,12 +430,12 @@ class Imap {
430 * 创建文件夹 430 * 创建文件夹
431 * $folder 目录 创建二级目录用/ a/b 431 * $folder 目录 创建二级目录用/ a/b
432 * @param string $folder 432 * @param string $folder
433 - * @return bool 433 + * @return string
434 * @throws \Exception 434 * @throws \Exception
435 * @author:dc 435 * @author:dc
436 * @time 2022/11/24 23:35 436 * @time 2022/11/24 23:35
437 */ 437 */
438 - public function folderCreate(string $folder):bool { 438 + public function folderCreate(string $folder):string {
439 // 需要转码 439 // 需要转码
440 $folder = mb_convert_encoding($folder,'UTF7-IMAP','UTF-8'); 440 $folder = mb_convert_encoding($folder,'UTF7-IMAP','UTF-8');
441 // A003 CREATE owatagusiam 顶级 441 // A003 CREATE owatagusiam 顶级
@@ -443,7 +443,7 @@ class Imap { @@ -443,7 +443,7 @@ class Imap {
443 $res = $this->request('CREATE '.$folder); 443 $res = $this->request('CREATE '.$folder);
444 444
445 if ($res[0] == 'ok'){ 445 if ($res[0] == 'ok'){
446 - return true; 446 + return $folder;
447 } 447 }
448 448
449 throw new \Exception('create folder error:'.end($res[1])); 449 throw new \Exception('create folder error:'.end($res[1]));
@@ -46,6 +46,20 @@ return [ @@ -46,6 +46,20 @@ return [
46 'mail/folder/create' => [\Controller\Folder::class, 'create'], 46 'mail/folder/create' => [\Controller\Folder::class, 'create'],
47 47
48 /** 48 /**
  49 + * 邮件/重命名文件夹
  50 + * @see \Controller\Folder::rename()
  51 + * @param string _token_ token登录凭证
  52 + */
  53 + 'mail/folder/rename' => [\Controller\Folder::class, 'rename'],
  54 +
  55 + /**
  56 + * 邮件/删除文件夹
  57 + * @see \Controller\Folder::delete()
  58 + * @param string _token_ token登录凭证
  59 + */
  60 + 'mail/folder/delete' => [\Controller\Folder::class, 'delete'],
  61 +
  62 + /**
49 * 发送邮件 63 * 发送邮件
50 * @see \Controller\Home::send_mail() 64 * @see \Controller\Home::send_mail()
51 * @param string _token_ token登录凭证 65 * @param string _token_ token登录凭证