<?php
/**
 * Rpc操作类
 */
class Rpc
{
    /**
     * 版本号
     * @var string
     */
    const VER = '0.0.1';

    // 下载种子的请求类型 GET POST
    public static $method = 'GET';
    // RPC连接池
    public static $links = array();
    /**
     * cookie
     */
    public static $cookies = '';
    /**
     * 浏览器 User-Agent
     */
    public static $userAgent = '';
    /**
     * passkey
     */
    public static $passkey = '';
    /**
     * 客户端配置
     */
    public static $clients = '';
    /**
     * 监控目录
     */
    public static $watch = '';
    /**
     * 种子存放路径
     */
    public static $torrentDir = '';
    /**
     * 工作模式
     */
    public static $workingMode = '';
    // 站点标识
    public static $site = '';
    /**
     * 负载均衡 控制变量
     */
    public static $RPC_Key = 0;
    /**
     * 退出状态码
     */
    public static $ExitCode = 0;
    /**
     * 初始化
     */
    public static function init($site = '', $method = 'GET')
    {
        global $configALL;

        self::$site = $site;
        self::$method = strtoupper($method);

        $config = $configALL[$site];
        self::$cookies = $config['cookie'];
        self::$userAgent = isset($config['userAgent']) && $config['userAgent'] ? $config['userAgent'] : $configALL['default']['userAgent'];
        self::$clients = isset($config['clients']) && $config['clients'] ? $config['clients'] : $configALL['default']['clients'];
        self::$workingMode = isset($config['workingMode']) && $config['workingMode'] ? $config['workingMode'] : 0;
        $watch = isset($config['watch']) && $config['watch'] ? $config['watch'] : $configALL['default']['watch'];
        self::$watch = rtrim($watch, '/') . DS;
        self::$torrentDir = TORRENT_PATH . $site . DS;
        // 建立目录
        IFile::mkdir(self::$torrentDir);
        
        self::links();
    }

    /**
     * 连接远端RPC服务器
     *
     * @param string
     * @return array
     */
    public static function links()
    {
        if (self::$workingMode === 1 && empty(self::$links)) {
            foreach (self::$clients as $k => $v) {
                // 跳过未配置的客户端
                if (empty($v['username']) || empty($v['password'])) {
                    unset(self::$clients[$k]);
                    echo "clients_".$k." 用户名或密码未配置,已跳过 \n\n";
                    continue;
                }
                try {
                    switch ($v['type']) {
                        case 'transmission':
                            self::$links[$k]['rpc'] = new TransmissionRPC($v['host'], $v['username'], $v['password']);
                            $result = self::$links[$k]['rpc']->sstats();
                            print $v['type'].':'.$v['host']." Rpc连接成功 [{$result->result}] \n";
                            break;
                        case 'qBittorrent':
                            self::$links[$k]['rpc'] = new qBittorrent($v['host'], $v['username'], $v['password']);
                            $result = self::$links[$k]['rpc']->appVersion();
                            print $v['type'].':'.$v['host']." Rpc连接成功 [{$result}] \n";
                            break;
                        case 'uTorrent':
                            self::$links[$k]['rpc'] = new uTorrent($v['host'], $v['username'], $v['password']);
                            $result = self::$links[$k]['rpc']->getBuild();
                            print $v['type'].':'.$v['host']." Rpc连接 [{$result}] \n";
                            break;
                        default:
                            echo '[ERROR] '.$v['type'];
                            exit(1);
                            break;
                    }
                    self::$links[$k]['type'] = $v['type'];
                    self::$links[$k]['downloadDir'] = $v['downloadDir'];
                } catch (Exception $e) {
                    echo '[ERROR] ' . $e->getMessage() . PHP_EOL;
                    exit(1);
                }
            }
        }
        return true;
    }

    /**
     * @brief 添加下载任务
     * @param string $torrent 种子元数据
     * @param string $save_path 保存路径
     * @return bool
     */
    public static function add($torrent, $save_path = '', $extra_options = array())
    {
        switch ((int)self::$workingMode) {
            case 0:		// watch默认工作模式
                // 复制到watch目录
                copy($torrent, $save_path);
                if (is_file($save_path)) {
                    print "********watch模式,下载任务添加成功 \n\n";
                    return true;
                } else {
                    print "-----watch模式,下载任务添加失败!!! \n\n";
                }
                break;
            case 1:		//负载均衡模式
                try {
                    $is_url = false;
                    if ((strpos($torrent, 'http://')===0) || (strpos($torrent, 'https://')===0) || (strpos($torrent, 'magnet:?xt=urn:btih:')===0)) {
                        $is_url = true;
                    }
                    // 负载均衡
                    $rpcKey = self::$RPC_Key;
                    echo '选中:负载均衡'.$rpcKey."\n";
                    self::rpcSelect();
                    // 调试
                    #p($result);
                    // 下载服务器类型 判断
                    $type = self::$links[$rpcKey]['type'];
                    switch ($type) {
                        case 'transmission':
                            if ($is_url) {
                                echo 'add';
                                $result = self::$links[$rpcKey]['rpc']->add($torrent, self::$links[$rpcKey]['downloadDir'], $extra_options);			// 种子URL添加下载任务
                            } else {
                                echo 'add_metainfo';
                                $result = self::$links[$rpcKey]['rpc']->add_metainfo($torrent, self::$links[$rpcKey]['downloadDir'], $extra_options);	// 种子文件添加下载任务
                            }
                            $id = $name = '';
                            if (isset($result->arguments->torrent_duplicate)) {
                                $id = $result->arguments->torrent_duplicate->id;
                                $name = $result->arguments->torrent_duplicate->name;
                            } elseif (isset($result->arguments->torrent_added)) {
                                $id = $result->arguments->torrent_added->id;
                                $name = $result->arguments->torrent_added->name;
                            }
                            if (!$id) {
                                print "-----RPC添加种子任务,失败 [{$result->result}] \n\n";
                            } else {
                                print "********RPC添加下载任务成功 [{$result->result}] (id=$id) \n\n";
                                // 新添加的任务,开始
                                self::$links[$rpcKey]['rpc']->start($id);
                                return true;
                            }
                            break;
                        case 'qBittorrent':
                            if ($is_url) {
                                echo 'add';
                                $result = self::$links[$rpcKey]['rpc']->add($torrent, self::$links[$rpcKey]['downloadDir'], $extra_options);			// 种子URL添加下载任务
                            } else {
                                echo 'add_metainfo';
                                $result = self::$links[$rpcKey]['rpc']->add_metainfo($torrent, self::$links[$rpcKey]['downloadDir'], $extra_options);	// 种子文件添加下载任务
                            }
                            if ($result === 'Ok.') {
                                print "********RPC添加下载任务成功 [{$result}] \n\n";
                                return true;
                            } else {
                                print "-----RPC添加种子任务,失败 [{$result}] \n\n";
                            }
                            break;
                        default:
                            echo '[ERROR] '.$type;
                            break;
                    }
                } catch (Exception $e) {
                    die('[ERROR] ' . $e->getMessage() . PHP_EOL);
                }
                break;
            case 2:
                echo "\n\n";
                # 暂未开放
                break;
            default:
                echo "\n\n";
                break;
        }
        return false;
    }

    /**
     * 负载均衡 选择算法
     *
     * @param
     * @return
     */
    public static function rpcSelect()
    {
        $clientsConut = count(self::$clients);
        if ($clientsConut > 1) {
            if ($clientsConut > (self::$RPC_Key+1)) {
                self::$RPC_Key++;
            } else {
                self::$RPC_Key = 0;
            }
        }
    }
    /**
     * @brief 种子处理函数
     * @param array $data 种子数组
     * Array
        (
            [id] => 118632
            [h1] => CCTV5+ 2019 ATP Men's Tennis Final 20191115B HDTV 1080i H264-HDxxx
            [title] => 央视体育赛事频道 2019年ATP男子网球年终总决赛 单打小组赛 纳达尔VS西西帕斯 20191115[优惠剩余时间:4时13分]
            [details] => https://XXX.me/details.php?id=118632
            [download] => https://XXX.me/download.php?id=118632
            [filename] => 118632.torrent
            [type] => 0
            [sticky] => 1
            [time] => Array
                (
                    [0] => "2019-11-16 20:41:53">4时13分
                    [1] => "2019-11-16 14:41:53">1时<br />46分
                )
            [comments] => 0
            [size] => 5232.64MB
            [seeders] => 69
            [leechers] => 10
            [completed] => 93
            [percentage] => 100%
            [owner] => 匿名
        )
     * @return
     */
    public static function call($data = array())
    {
        foreach ($data as $key => $value) {
            // 控制台打印
            echo '主标题:'.$value['h1']."\n";
            echo '副标题:'.$value['title']."\n";
            echo '详情页:'.$value['details']."\n";
            if ($value['type'] != 0) {
                echo "-----非免费,已忽略! \n\n";
                continue;
            }
            if (isset($value['hr']) && ($value['hr'] == 1)) {
                echo "-----HR种子,已忽略! \n\n";
                continue;
            }
            // 下载任务的可选参数
            $extra_options = array();
            // 保存的文件名
            $filename = $value['id'] . '.torrent';
            // 默认watch工作模式,复制到此目录
            $to = self::$watch . $filename;
            // 种子完整存放路径
            $torrentFile = self::$torrentDir . $filename;
            if (is_file($torrentFile)) {
                $fileSize = filesize($torrentFile);		//失败会返回false 或 0(0代表上次下载失败)
                if (!empty($fileSize)) {
                    //种子已经存在
                    echo '-----存在旧种子:'.$filename."\n\n";
                    continue;
                }
                // 删除下载错误的文件
                IFile::unlink($torrentFile);
            }
            
            // 调用过滤函数
            $isFilter = filter(self::$site, $value);
            if (is_string($isFilter)) {
                echo "-----" .$isFilter. "\n\n";
                continue;
            }
            //种子不存在
            echo '正在下载新种子... '.$value['download']." \n";
            // 创建文件、下载种子以二进制写入
            $content = '';
            $content = download($value['download'], self::$cookies, self::$userAgent, self::$method);
            #p($content);
            // 文件句柄
            $resource = fopen($torrentFile, "wb");
            // 成功:返回写入字节数,失败返回false
            $worldsnum = fwrite($resource, $content);
            // 关闭
            fclose($resource);
            // 判断
            if (is_bool($worldsnum)) {
                print "种子下载失败!!! \n\n";
                IFile::unlink($torrentFile);
                continue;
            } else {
                print "成功下载种子" . $filename . ',共计:' . $worldsnum . "字节 \n";
                sleep(mt_rand(2, 10));
                $ret = false;
                $rpcKey = self::$RPC_Key;
                switch ((int)self::$workingMode) {
                    case 0:		//默认工作模式
                        $ret = self::add($torrentFile, $to);
                        break;
                    case 1:		//负载均衡模式
                        $type = self::$links[$rpcKey]['type'];
                        // 下载服务器类型
                        switch ($type) {
                            case 'transmission':
                                # code...
                                break;
                            case 'qBittorrent':
                                $extra_options['name'] = 'torrents';
                                $extra_options['filename'] = $filename;
                                $extra_options['autoTMM'] = 'false';	//关闭自动种子管理
                                break;
                            default:
                                # code...
                                break;
                        }
                        // 种子文件添加下载任务
                        $ret = self::add($content, $to, $extra_options);
                        break;
                    case 2:
                        echo "\n\n";
                        # 暂未开放
                        break;
                    default:
                        echo "\n\n";
                        break;
                }
                global $configALL;
                if (isset($configALL['iyuu.cn']) && ($ret === true)) {
                    send(self::$site, $value);
                }
            }
        }
        return true;
    }
}