SyncMailList.php 4.4 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\MySQL;
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需要的配置
        ]);


        run(function () use ($rand,$max_coroutine){
            // 获取邮箱总数量
            $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 携程中无法使用laravel的cache的redis驱动
                        $redis  =   swoole_redis();
                        $db =   swoole_db();
                        $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) {
                                try {
                                    $this->sync($n,$db);
                                }catch (\Throwable $e){
                                    echo "协程(".\co::getCid()."):".$e->getMessage();
                                }

                            }

                            $n++;
                        }
                        $redis->close();
                        $db->close();
                        $redis = $db = null;

                    });
                }
            }

        });

        return Command::SUCCESS;
    }

    /**
     * 开始同步执行
     * @param int $n
     * @param MySQL $db
     * @author:dc
     * @time 2023/2/9 11:40
     */
    private function sync(int $n,MySQL $db){

        /** @var $email Email */
        $email = swoole_db_first(
            $db,
            'select * from `emails` where `id` = '.$n
        );

        // 密码没有错误,且状态正常的
        if ($email && $email['pwd_error'] == 0 && $email['status'] == Email::STATUS_ACTIVE){
            // 登录imap服务器
            Mail::login($email['email'],base64_decode($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']);
                    }
                }

            }
        }

    }



}