SyncMailList.php 4.1 KB
<?php

namespace App\Console\Commands;

use App\Models\Email;
use App\Models\Folder;
use Helper\Mail\Mail;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Swoole\Coroutine\Redis;
use function Co\run;

class SyncMailList extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'SyncMailList';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '同步邮箱的邮件到本地';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {

        // 这个是防止前一个任务没有完成,反而无法取得资源。
        $rand = date('dHi');
        // 携程数量越大,需要的内存越大
        $max_coroutine  =   10000;
        // swoole全局设置,需要在swoole运行前设置
        \co::set([
            'max_coroutine'=>$max_coroutine, // 最大携程数量
            'hook_flags'=>SWOOLE_HOOK_TCP,  //  redis需要的配置
        ]);

        // redis 配置
        $redis_config =   [
            'host'    =>  env('REDIS_HOST','127.0.0.1'),
            'port'  =>  env('REDIS_PORT',6379),
            'password'  =>  env('REDIS_PASSWORD',null)
        ];

        run(function () use ($rand,$max_coroutine,$redis_config){
            // 获取邮箱总数量
            $size = Email::where([])->count();
            // 最后一条数据的id
            $lastId = Email::where([])->orderBy('id','desc')->value('id');
            // 创建的携程数量
            $max_coroutine = $size > $max_coroutine ? $max_coroutine : $size;
            if ($max_coroutine){
                for ($i = $max_coroutine; $i > 0; $i--) {
                    // 创建携程
                    go(function () use ($size,$rand,$lastId,$redis_config){

                        // redis 携程中无法使用laravel的cache的redis驱动
                        $redis  =   swoole_redis();

                        $n = 1;
                        while ($n <= $lastId){
                            echo 'syncMail'.$rand.':'.$n;echo PHP_EOL;
                            // 使用lua脚本
                            $add = $redis->eval(
                                ...swoole_redis_add('syncMail'.$rand.':'.$n,$n,7200)
                            );
                            // 是否已存在
                            if($add) {
                                $this->sync($n);
                            }

                            $n++;
                        }

                    });
                }
            }

        });

        return Command::SUCCESS;
    }

    /**
     * 开始同步执行
     * @param int $n 第几条数据
     * @author:dc
     * @time 2023/2/5 17:21
     */
    private function sync(int $n = 0){

        /** @var $email Email */
        $email = Email::where(['id'=>$n])->first();
        // 密码没有错误,且状态正常的
        if ($email && $email->pwd_error == 0 && $email->status == Email::STATUS_ACTIVE){
            // 登录imap服务器
            Mail::login($email->email,$email->password,$email->imap);
            // 设置id
            Mail::$client[$email->email]->setId($email->id);
            // 同步文件夹
            Mail::syncFolder($email->email);

            // 获取当前邮箱的所有文件夹
            $folders =   Folder::_all($email->id);
            // 目前只发现最高2级
            foreach ($folders as $folder){
                if(empty($folder['_child'])){
                    // 同步邮件
                    Mail::syncMail($email->email,$email->id,$folder['id'],$folder['origin_folder']);
                }else{
                    // 循环子级目录,有子级的情况,父级不可操作,且不会有邮件
                    foreach ($folder['_child'] as $f){
                        // 同步邮件
                        Mail::syncMail($email->email,$email->id,$f['id'],$folder['origin_folder'].'/'.$f['origin_folder']);
                    }
                }

            }
        }

    }



}