作者 邓超

1

@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 2
3 namespace App\Console\Commands; 3 namespace App\Console\Commands;
4 4
  5 +use App\Models\EList;
5 use Helper\Mail\Mail; 6 use Helper\Mail\Mail;
6 use Illuminate\Console\Command; 7 use Illuminate\Console\Command;
7 use function Co\run; 8 use function Co\run;
@@ -30,29 +31,33 @@ class Demo extends Command @@ -30,29 +31,33 @@ class Demo extends Command
30 public function handle() 31 public function handle()
31 { 32 {
32 33
33 - run(function (){  
34 - go(function (){  
35 -  
36 - $redis = swoole_redis();  
37 -// $a = $redis->eval(...swoole_redis_add('asdad:1',1,600));  
38 -// var_dump($a);  
39 - $redis->rPush('syncMailBody',300);  
40 -// $redis->rPush('syncMailBody',301);  
41 -// $redis->rPush('syncMailBody',302);  
42 -// $redis->rPush('syncMailBody',303);  
43 -// $redis->rPush('syncMailBody',304);  
44 -// $redis->rPush('syncMailBody',305);  
45 -// $redis->rPush('syncMailBody',306);  
46 -// $redis->rPush('syncMailBody',307);  
47 -// $redis->rPush('syncMailBody',308);  
48 -// $redis->rPush('syncMailBody',309);  
49 -  
50 - $redis->set('syncmailbodystop',1);  
51 -  
52 - });  
53 -  
54 - });  
55 - 34 +// run(function (){
  35 +// go(function (){
  36 +//
  37 +//
  38 +// $redis = swoole_redis();
  39 +////// $a = $redis->eval(...swoole_redis_add('asdad:1',1,600));
  40 +////// var_dump($a);
  41 +// for ($i=1;$i<=345;$i++){
  42 +// $redis->rPush('syncMailBody',$i);
  43 +// }
  44 +//
  45 +//// $redis->rPush('syncMailBody',301);
  46 +//// $redis->rPush('syncMailBody',302);
  47 +//// $redis->rPush('syncMailBody',303);
  48 +//// $redis->rPush('syncMailBody',304);
  49 +//// $redis->rPush('syncMailBody',305);
  50 +//// $redis->rPush('syncMailBody',306);
  51 +//// $redis->rPush('syncMailBody',307);
  52 +//// $redis->rPush('syncMailBody',308);
  53 +//// $redis->rPush('syncMailBody',309);
  54 +//
  55 +// $redis->set('syncmailbodystop',1);
  56 +//
  57 +// });
  58 +//
  59 +// });
  60 +//
56 61
57 62
58 63
@@ -9,6 +9,7 @@ use Helper\Mail\Mail; @@ -9,6 +9,7 @@ use Helper\Mail\Mail;
9 use Illuminate\Console\Command; 9 use Illuminate\Console\Command;
10 use Illuminate\Support\Facades\Cache; 10 use Illuminate\Support\Facades\Cache;
11 use Illuminate\Support\Facades\Log; 11 use Illuminate\Support\Facades\Log;
  12 +use Swoole\Coroutine\MySQL;
12 use Swoole\Coroutine\Redis; 13 use Swoole\Coroutine\Redis;
13 use function Co\run; 14 use function Co\run;
14 15
@@ -51,14 +52,16 @@ class SyncBody extends Command @@ -51,14 +52,16 @@ class SyncBody extends Command
51 go(function () { 52 go(function () {
52 // 需要获取邮件的id 53 // 需要获取邮件的id
53 $isRun = true; 54 $isRun = true;
54 - while ($isRun){  
55 // @var $redis 这个必须放携程里面 55 // @var $redis 这个必须放携程里面
56 $redis = swoole_redis(); 56 $redis = swoole_redis();
  57 + $db = swoole_db();
  58 + while ($isRun){
  59 +
57 // 获取到邮件的数据id 60 // 获取到邮件的数据id
58 $id = $redis->lPop('syncMailBody'); 61 $id = $redis->lPop('syncMailBody');
59 62
60 if($id){ 63 if($id){
61 - $this->sync($redis,$id); 64 + $this->sync($redis,$db,$id);
62 }else { 65 }else {
63 // 暂停1秒 66 // 暂停1秒
64 \co::sleep(1); 67 \co::sleep(1);
@@ -69,11 +72,14 @@ class SyncBody extends Command @@ -69,11 +72,14 @@ class SyncBody extends Command
69 if($redis->get('syncmailbodystop') == 1){ 72 if($redis->get('syncmailbodystop') == 1){
70 $isRun = false; 73 $isRun = false;
71 } 74 }
72 - // 关闭redis 75 +
  76 + }
  77 +// 关闭redis
73 $redis->close(); 78 $redis->close();
74 $redis = null; 79 $redis = null;
75 - }  
76 80
  81 + $db->close();
  82 + $db = null;
77 83
78 }); 84 });
79 } 85 }
@@ -88,33 +94,40 @@ class SyncBody extends Command @@ -88,33 +94,40 @@ class SyncBody extends Command
88 /** 94 /**
89 * 执行 95 * 执行
90 * @param $redis Redis 96 * @param $redis Redis
  97 + * @param $db MySQL
91 * @param $id 98 * @param $id
92 * @author:dc 99 * @author:dc
93 * @time 2023/2/8 11:44 100 * @time 2023/2/8 11:44
94 */ 101 */
95 - public function sync(&$redis,$id){ 102 + public function sync(&$redis,$db,$id){
96 try { 103 try {
97 // 先暂用,锁上这个id 104 // 先暂用,锁上这个id
98 if($redis->eval(...swoole_redis_add('syncmailbodyrun:'.$id,$id,3))){ 105 if($redis->eval(...swoole_redis_add('syncmailbodyrun:'.$id,$id,3))){
99 $this->echoStr('number:'.$id); 106 $this->echoStr('number:'.$id);
100 // 读取邮件信息 107 // 读取邮件信息
101 - $mail = EList::where('id',$id)->first(); 108 + $mail = swoole_db_first(
  109 + $db,
  110 + 'select `id`,`uid`,`msgno`,`folder_id`,`email_id` from `lists` where `id` = '.$id
  111 + );
102 if(!$mail){ 112 if(!$mail){
103 return false; 113 return false;
104 } 114 }
105 115
106 - $email_id = $mail->email_id;  
107 - $folder_id = $mail->folder_id; 116 + $email_id = $mail['email_id'];
  117 + $folder_id = $mail['folder_id'];
108 118
109 /*** 获取邮箱信息 ***/ 119 /*** 获取邮箱信息 ***/
110 $email_key = 'email_list:'.$email_id; 120 $email_key = 'email_list:'.$email_id;
111 // 判断是否有携程在查询了 121 // 判断是否有携程在查询了
112 if($redis->eval(...swoole_redis_add($email_key,1,600))){ 122 if($redis->eval(...swoole_redis_add($email_key,1,600))){
113 // 查询邮箱 123 // 查询邮箱
114 - $emailModel = Email::where('id',$email_id)->first(); 124 + $emailModel = swoole_db_first(
  125 + $db,
  126 + 'select * from `emails` where `id` = '.$email_id
  127 + );
115 if($emailModel){ 128 if($emailModel){
116 // 设置缓存 129 // 设置缓存
117 - $redis->set($email_key,$emailModel->toArray(),600); 130 + $redis->set($email_key,$emailModel,600);
118 }else { 131 }else {
119 // 删除缓存 132 // 删除缓存
120 $redis->delete($email_key); 133 $redis->delete($email_key);
@@ -169,14 +182,17 @@ class SyncBody extends Command @@ -169,14 +182,17 @@ class SyncBody extends Command
169 } 182 }
170 $this->echoStr('目录:'.$folder_name); 183 $this->echoStr('目录:'.$folder_name);
171 if($folder_name){ 184 if($folder_name){
  185 + // 登录imap服务器
  186 + Mail::login($email,$password,$imap);
  187 + // 设置id
  188 + Mail::$client[$email]->setId($email_id);
  189 +
172 Mail::syncBody( 190 Mail::syncBody(
173 $id, 191 $id,
174 - $mail->msgno, 192 + $mail['msgno'],
175 $email_id, 193 $email_id,
176 $folder_name, 194 $folder_name,
177 - $email,  
178 - $password,  
179 - $imap 195 + $email
180 ); 196 );
181 } 197 }
182 } 198 }
@@ -8,6 +8,7 @@ use Helper\Mail\Mail; @@ -8,6 +8,7 @@ use Helper\Mail\Mail;
8 use Illuminate\Console\Command; 8 use Illuminate\Console\Command;
9 use Illuminate\Support\Facades\Cache; 9 use Illuminate\Support\Facades\Cache;
10 use Illuminate\Support\Facades\Log; 10 use Illuminate\Support\Facades\Log;
  11 +use Swoole\Coroutine\MySQL;
11 use Swoole\Coroutine\Redis; 12 use Swoole\Coroutine\Redis;
12 use function Co\run; 13 use function Co\run;
13 14
@@ -45,14 +46,8 @@ class SyncMailList extends Command @@ -45,14 +46,8 @@ class SyncMailList extends Command
45 'hook_flags'=>SWOOLE_HOOK_TCP, // redis需要的配置 46 'hook_flags'=>SWOOLE_HOOK_TCP, // redis需要的配置
46 ]); 47 ]);
47 48
48 - // redis 配置  
49 - $redis_config = [  
50 - 'host' => env('REDIS_HOST','127.0.0.1'),  
51 - 'port' => env('REDIS_PORT',6379),  
52 - 'password' => env('REDIS_PASSWORD',null)  
53 - ];  
54 49
55 - run(function () use ($rand,$max_coroutine,$redis_config){ 50 + run(function () use ($rand,$max_coroutine){
56 // 获取邮箱总数量 51 // 获取邮箱总数量
57 $size = Email::where([])->count(); 52 $size = Email::where([])->count();
58 // 最后一条数据的id 53 // 最后一条数据的id
@@ -62,11 +57,11 @@ class SyncMailList extends Command @@ -62,11 +57,11 @@ class SyncMailList extends Command
62 if ($max_coroutine){ 57 if ($max_coroutine){
63 for ($i = $max_coroutine; $i > 0; $i--) { 58 for ($i = $max_coroutine; $i > 0; $i--) {
64 // 创建携程 59 // 创建携程
65 - go(function () use ($size,$rand,$lastId,$redis_config){ 60 + go(function () use ($size,$rand,$lastId){
66 61
67 // redis 携程中无法使用laravel的cache的redis驱动 62 // redis 携程中无法使用laravel的cache的redis驱动
68 $redis = swoole_redis(); 63 $redis = swoole_redis();
69 - 64 + $db = swoole_db();
70 $n = 1; 65 $n = 1;
71 while ($n <= $lastId){ 66 while ($n <= $lastId){
72 echo 'syncMail'.$rand.':'.$n;echo PHP_EOL; 67 echo 'syncMail'.$rand.':'.$n;echo PHP_EOL;
@@ -76,11 +71,19 @@ class SyncMailList extends Command @@ -76,11 +71,19 @@ class SyncMailList extends Command
76 ); 71 );
77 // 是否已存在 72 // 是否已存在
78 if($add) { 73 if($add) {
79 - $this->sync($n); 74 + try {
  75 + $this->sync($n,$db);
  76 + }catch (\Throwable $e){
  77 + echo "协程(".\co::getCid()."):".$e->getMessage();
  78 + }
  79 +
80 } 80 }
81 81
82 $n++; 82 $n++;
83 } 83 }
  84 + $redis->close();
  85 + $db->close();
  86 + $redis = $db = null;
84 87
85 }); 88 });
86 } 89 }
@@ -93,35 +96,40 @@ class SyncMailList extends Command @@ -93,35 +96,40 @@ class SyncMailList extends Command
93 96
94 /** 97 /**
95 * 开始同步执行 98 * 开始同步执行
96 - * @param int $n 第几条数据 99 + * @param int $n
  100 + * @param MySQL $db
97 * @author:dc 101 * @author:dc
98 - * @time 2023/2/5 17:21 102 + * @time 2023/2/9 11:40
99 */ 103 */
100 - private function sync(int $n = 0){ 104 + private function sync(int $n,MySQL $db){
101 105
102 /** @var $email Email */ 106 /** @var $email Email */
103 - $email = Email::where(['id'=>$n])->first(); 107 + $email = swoole_db_first(
  108 + $db,
  109 + 'select * from `emails` where `id` = '.$n
  110 + );
  111 +
104 // 密码没有错误,且状态正常的 112 // 密码没有错误,且状态正常的
105 - if ($email && $email->pwd_error == 0 && $email->status == Email::STATUS_ACTIVE){ 113 + if ($email && $email['pwd_error'] == 0 && $email['status'] == Email::STATUS_ACTIVE){
106 // 登录imap服务器 114 // 登录imap服务器
107 - Mail::login($email->email,$email->password,$email->imap); 115 + Mail::login($email['email'],base64_decode($email['password']),$email['imap']);
108 // 设置id 116 // 设置id
109 - Mail::$client[$email->email]->setId($email->id); 117 + Mail::$client[$email['email']]->setId($email['id']);
110 // 同步文件夹 118 // 同步文件夹
111 - Mail::syncFolder($email->email); 119 + Mail::syncFolder($email['email']);
112 120
113 // 获取当前邮箱的所有文件夹 121 // 获取当前邮箱的所有文件夹
114 - $folders = Folder::_all($email->id); 122 + $folders = Folder::_all($email['id']);
115 // 目前只发现最高2级 123 // 目前只发现最高2级
116 foreach ($folders as $folder){ 124 foreach ($folders as $folder){
117 if(empty($folder['_child'])){ 125 if(empty($folder['_child'])){
118 // 同步邮件 126 // 同步邮件
119 - Mail::syncMail($email->email,$email->id,$folder['id'],$folder['origin_folder']); 127 + Mail::syncMail($email['email'],$email['id'],$folder['id'],$folder['origin_folder']);
120 }else{ 128 }else{
121 // 循环子级目录,有子级的情况,父级不可操作,且不会有邮件 129 // 循环子级目录,有子级的情况,父级不可操作,且不会有邮件
122 foreach ($folder['_child'] as $f){ 130 foreach ($folder['_child'] as $f){
123 // 同步邮件 131 // 同步邮件
124 - Mail::syncMail($email->email,$email->id,$f['id'],$folder['origin_folder'].'/'.$f['origin_folder']); 132 + Mail::syncMail($email['email'],$email['id'],$f['id'],$folder['origin_folder'].'/'.$f['origin_folder']);
125 } 133 }
126 } 134 }
127 135
@@ -50,6 +50,7 @@ class MailApi @@ -50,6 +50,7 @@ class MailApi
50 50
51 $model->imap = $formData['imap']; 51 $model->imap = $formData['imap'];
52 $model->smtp = $formData['smtp']; 52 $model->smtp = $formData['smtp'];
  53 + $model->status = Email::STATUS_ACTIVE;
53 $model->password = @base64_encode($formData['password']); 54 $model->password = @base64_encode($formData['password']);
54 55
55 try { 56 try {
@@ -877,8 +877,9 @@ class Imap { @@ -877,8 +877,9 @@ class Imap {
877 * @author:dc 877 * @author:dc
878 * @time 2022/11/25 11:15 878 * @time 2022/11/25 11:15
879 */ 879 */
880 - public function noop():void {  
881 - $this->request('NOOP'); 880 + public function noop():bool {
  881 + $status = $this->request('NOOP');
  882 + return $status[0] == 'ok';
882 } 883 }
883 884
884 /** 885 /**
@@ -35,10 +35,16 @@ class Mail { @@ -35,10 +35,16 @@ class Mail {
35 * @time 2023/2/5 10:46 35 * @time 2023/2/5 10:46
36 */ 36 */
37 public static function login(string $email,string $password,string $imap) { 37 public static function login(string $email,string $password,string $imap) {
  38 + if(!empty(static::$client[$email]) && static::$client[$email] instanceof Imap){
  39 + if(static::$client[$email]->noop()){
  40 + return true;
  41 + }
  42 + }
38 static::$client[$email] = new Imap(); 43 static::$client[$email] = new Imap();
39 // $imap->debug(); 44 // $imap->debug();
40 // 是否初始成功 45 // 是否初始成功
41 static::$client[$email]->login("ssl://{$imap}:993",$email,$password); 46 static::$client[$email]->login("ssl://{$imap}:993",$email,$password);
  47 + return true;
42 } 48 }
43 49
44 50
@@ -89,7 +95,7 @@ class Mail { @@ -89,7 +95,7 @@ class Mail {
89 public static function syncMail($email,$email_id,$folder_id,$folder='INBOX'):bool { 95 public static function syncMail($email,$email_id,$folder_id,$folder='INBOX'):bool {
90 // 选择文件夹 96 // 选择文件夹
91 try { 97 try {
92 - $status = Mail::$client[$email]->selectFolder($folder); 98 + $status = static::$client[$email]->selectFolder($folder);
93 }catch (\Throwable $e){ 99 }catch (\Throwable $e){
94 Log::error($email.' 选择文件夹错误:'.$e->getMessage()); 100 Log::error($email.' 选择文件夹错误:'.$e->getMessage());
95 return false; 101 return false;
@@ -128,7 +134,7 @@ class Mail { @@ -128,7 +134,7 @@ class Mail {
128 $dataids = EList::_getIdsByMsgno($email_id,$folder_id,$msgno); 134 $dataids = EList::_getIdsByMsgno($email_id,$folder_id,$msgno);
129 135
130 // 循环 136 // 循环
131 - $results = Mail::$client[$email]->fetchHeader($msgno); 137 + $results = static::$client[$email]->fetchHeader($msgno);
132 138
133 if($results){ 139 if($results){
134 DB::beginTransaction(); 140 DB::beginTransaction();
@@ -211,23 +217,17 @@ class Mail { @@ -211,23 +217,17 @@ class Mail {
211 * @param $email_id 217 * @param $email_id
212 * @param $folder_name 218 * @param $folder_name
213 * @param $email 219 * @param $email
214 - * @param $password  
215 - * @param $imap  
216 * @return bool 220 * @return bool
217 * @throws \Exception 221 * @throws \Exception
218 * @author:dc 222 * @author:dc
219 - * @time 2023/2/8 13:45 223 + * @time 2023/2/9 10:29
220 */ 224 */
221 - public static function syncBody($id,$msgno, $email_id,$folder_name,$email, $password,$imap):bool { 225 + public static function syncBody($id,$msgno, $email_id,$folder_name,$email):bool {
222 226
223 - // 登录imap服务器  
224 - Mail::login($email,$password,$imap);  
225 - // 设置id  
226 - Mail::$client[$email]->setId($email_id);  
227 // 选择文件夹 227 // 选择文件夹
228 - Mail::$client[$email]->selectFolder($folder_name); 228 + static::$client[$email]->selectFolder($folder_name);
229 229
230 - $body = Mail::$client[$email]->fetchBody([$msgno],storage_path('email/'.$email_id)); 230 + $body = static::$client[$email]->fetchBody([$msgno],storage_path('email/'.$email_id));
231 231
232 if(!empty($body[$msgno]['RFC822.TEXT'])){ 232 if(!empty($body[$msgno]['RFC822.TEXT'])){
233 \App\Models\Body::_insert($id,$body[$msgno]['RFC822.TEXT']); 233 \App\Models\Body::_insert($id,$body[$msgno]['RFC822.TEXT']);
@@ -144,6 +144,40 @@ function swoole_redis_add($key,$val,$ttl=-1):array { @@ -144,6 +144,40 @@ function swoole_redis_add($key,$val,$ttl=-1):array {
144 ]; 144 ];
145 } 145 }
146 146
  147 +/**
  148 + * swoole 操作db
  149 + * @return \Swoole\Coroutine\MySQL
  150 + * @author:dc
  151 + * @time 2023/2/8 16:48
  152 + */
  153 +function swoole_db():\Swoole\Coroutine\MySQL{
  154 +
  155 + $swoole_mysql = new \Swoole\Coroutine\MySQL();
  156 +
  157 + $swoole_mysql->connect([
  158 + 'host' => env('DB_HOST','127.0.0.1'),
  159 + 'port' => env('DB_PORT',3306),
  160 + 'user' => env('DB_USERNAME'),
  161 + 'password' => env('DB_PASSWORD'),
  162 + 'database' => env('DB_DATABASE'),
  163 + ]);
  164 +
  165 + return $swoole_mysql;
  166 +}
  167 +
  168 +/**
  169 + * 查询一条
  170 + * @param $db \Swoole\Coroutine\MySQL
  171 + * @param $query
  172 + * @return mixed
  173 + * @author:dc
  174 + * @time 2023/2/8 17:15
  175 + */
  176 +function swoole_db_first(&$db,$query){
  177 + $row = $db->query($query);
  178 + return $row[0]??null;
  179 +}
  180 +
147 181
148 182
149 183