   'phpDocumentor\Descriptor\FileDescriptor * hash bd0417083608f000b761d987e5c56934 * pathClient/ConcurrentClient.php	 * source\<?php
/**
 * 并行的兼容Flex标准的HTTP客户端
 *
 * 不推荐使用将来可能废弃，建议使用\PG\MSF\Client\Http\Client::goConcurrent($requests)
 *
 * @author camera360_server@camera360.com
 * @copyright Chengdu pinguo Technology Co.,Ltd.
 */

namespace PG\MSF\Client;

use PG\Exception\BusinessException;
use PG\MSF\Base\Core;
use PG\MSF\Client\Http\Client;
use PG\MSF\Coroutine\Dns;

/**
 * Class ConcurrentClient
 * @package PG\MSF\Client
 */
class ConcurrentClient
{
    /**
     * @var array json errors
     */
    protected static $jsonErrors = [
        JSON_ERROR_NONE => null,
        JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
        JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch',
        JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
        JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
        JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
    ];

    /**
     * 并行请求
     *
     * @param array $requests 请求的数据
     * @param Core $parent Core实例（通常为Controller实例）
     * @return array
     */
    public static function request(array $requests, Core $parent)
    {
        $config = $parent->getConfig();
        $serviceConf = $config->get('params.service', null);
        $parallelConf = $config->get('params.parallel');

        $preParams = array_filter([
            '__appVersion' => !empty($parent->getContext()->getInput()->postGet('__appVersion')) ? $parent->getContext()->getInput()->postGet('__appVersion') : $parent->getContext()->getInput()->postGet('appVersion'),
            '__locale' => !empty($parent->getContext()->getInput()->postGet('__locale')) ? $parent->getContext()->getInput()->postGet('__locale') : $parent->getContext()->getInput()->postGet('locale'),
            '__platform' => !empty($parent->getContext()->getInput()->postGet('__platform')) ? $parent->getContext()->getInput()->postGet('__platform') : $parent->getContext()->getInput()->postGet('platform')
        ]);

        $list = $result = [];
        foreach ($requests as $name => $params) {
            if (isset($parallelConf[$name])) {
                //服务名
                $list[$name]['service'] = $service = $parallelConf[$name]['service'] ?? null;
                $list[$name]['host'] = $parallelConf[$name]['host'] ?? $serviceConf[$service]['host'];
                $list[$name]['timeout'] = $parallelConf[$name]['timeout'] ?? $serviceConf[$service]['timeout'] ?? 1000;
                $list[$name]['api'] = $parallelConf[$name]['url'];
                //优先使用parallel配置，然后有参数有POST，无参用GET
                $list[$name]['method'] = $parallelConf[$name]['method'] ?? (empty($params) ? 'GET' : 'POST');
                $list[$name]['params'] = array_merge($params, $preParams); //合并参数;
                //结果解析方法
                $list[$name]['parser'] = ($parallelConf[$name]['parser'] ?? 'normal') . 'Parser';

                //dns请求
                $list[$name]['dns'] = $parent->getObject(Client::class)->goDnsLookup($list[$name]['host'], $list[$name]['timeout']);
            }
        }

        foreach ($list as $name => $item) {
            /**
             * @var Client $client
             */
            //dns结果
            if ($item['dns'] instanceof DNS) {
                $item['dns'] = $item['dns'];
                if (!$item['dns']) {
                    $parent->getContext()->getLog()->error('DNS lookup for ' . $item['host'] . ' Failed');
                    $result[$name] = false;
                    unset($list[$name]);
                    continue;
                }
            }

            //http请求
            if ($item['method'] == 'POST') {
                $list[$name]['http'] = $item['dns']->goPost($item['api'], $item['params'], $item['timeout']);
            } else {
                $list[$name]['http'] = $item['dns']->goGet($item['api'], $item['params'], $item['timeout']);
            }
        }

        foreach ($list as $name => $item) {
            $response = $item['http'];

            $request = ['host' => $item['host'], 'api' => $item['api'], 'method' => $item['method'], 'params' => $item['params']];

            // http 失败
            if (!isset($response['body']) || empty($response['body'])) {
                $parent->getContext()->getLog()->error('The response of body is not found with response: ' . json_encode($response) . ' Request: ' . json_encode($request));
                $result[$name] = false;
                unset($list[$name]);
                continue;
            }

            //解析结果
            $parser = $item['parser'];
            $result[$name] = $parser === 'noneParser' ? $response : self::$parser($request, $response, $parent);
        }

        return $result;
    }

    /**
     * 结果解析器(常规)
     *
     * @param array $request 请求信息
     * @param array $response 响应数据
     * @param Core $parent Core实例（通常为Controller实例）
     * @return mixed|null
     */
    protected static function normalParser(array $request, array $response, Core $parent)
    {
        try {
            $body = json_decode($response['body'], true);
            if ($body === null) {
                $error = static::jsonLastErrorMsg();
                throw new BusinessException('json decode failure: ' . $error . ' caused by ' . $response['body'] . ' Request: ' . json_encode($request));
            }

            return static::parseResponse($request, $body);
        } catch (BusinessException $businessException) {
            $parent->getContext()->getLog()->error($businessException->getMessage());
            return null;
        }
    }

    /**
     * 解析返回值
     *
     * @param array $request 请求参数
     * @param array $responseBody 响应正文
     * @return mixed
     * @throws BusinessException
     */
    private static function parseResponse(array $request, $responseBody)
    {
        if (isset($responseBody['status']) == false
            || array_key_exists('data', $responseBody) == false
            || isset($responseBody['message']) == false
        ) {
            throw new BusinessException('Response The result array is incomplete. response=' . json_encode($responseBody) . ' Request: ' . json_encode($request));
        }
        if ($responseBody['status'] != 200) {
            throw new BusinessException('Response returns the result status is not equal to 200. response=' . json_encode($responseBody) . ' Request: ' . json_encode($request));
        }

        return $responseBody['data'];
    }

    /**
     * 拿到json解析最后出现的错误信息
     *
     * @return mixed|string
     */
    private static function jsonLastErrorMsg()
    {
        $error = json_last_error();
        return array_key_exists($error, static::$jsonErrors) ? static::$jsonErrors[$error] : "Unknown error ({$error})";
    }
}
 * namespaceAliases#phpDocumentor\Descriptor\Collection * itemsBusinessException\PG\Exception\BusinessExceptionCore\PG\MSF\Base\CoreClient\PG\MSF\Client\Http\ClientDns\PG\MSF\Coroutine\Dns * includes	  * constants	  * functions	 
 * classes	\PG\MSF\Client\ConcurrentClient(phpDocumentor\Descriptor\ClassDescriptor	 * parent * implements	  * abstract * final	  * properties	
jsonErrors+phpDocumentor\Descriptor\PropertyDescriptor" * types 
 * defaultTarray(JSON_ERROR_NONE => null, JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch', JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded')	 * static * visibility	protected * fqsen+\PG\MSF\Client\ConcurrentClient::jsonErrors * name * namespace 
 * package
 * summary * description * fileDescriptor  * line * tags	var	 *phpDocumentor\Descriptor\Tag\VarDescriptor * variableName	 3phpDocumentor\Descriptor\Type\UnknownTypeDescriptor'array'/+json errors	 * errors	 5	  * inheritedElement 
 * methods	request)phpDocumentor\Descriptor\MethodDescriptor""#public * arguments		$requests+phpDocumentor\Descriptor\ArgumentDescriptor	 * method"!	 2'3   * byReference * isVariadic%'<( )*+请求的数据, - .	 5	 6 $parent=>"!	 2'  ?@%'B( )*+)Core实例（通常为Controller实例）, - .	 5	 6 %*\PG\MSF\Client\ConcurrentClient::request()'8( )*并行请求+, -+.	param	 ,phpDocumentor\Descriptor\Tag\ParamDescriptor1<"%'F+A5	 G1B"-'F+C5	 return	 -phpDocumentor\Descriptor\Tag\ReturnDescriptor	 2'3'H+5	 5	 6 normalParser9""#$;	$request=>"H	 2'3  ?@%'K( )*+请求信息, - .	 5	 6 	$response=>"H	 2'3  ?@%'M( )*+响应数据, - .	 5	 6 B=>"H	 2'  ?@%'B( )*+C, - .	 5	 6 %/\PG\MSF\Client\ConcurrentClient::normalParser()'J( )*结果解析器(常规)+, -~.	F	 G1K"L'F+L5	 G1M"T'F+N5	 G1B"\'F+C5	 H	 I	 2'mixed2'null'H+5	 5	 6 parseResponse9""#private;	K=>"{	 2'3  ?@%'K( )*+请求参数, - .	 5	 6 $responseBody=>"{	 2'3  ?@%'V( )*+响应正文, - .	 5	 6 %0\PG\MSF\Client\ConcurrentClient::parseResponse()'S( )*解析返回值+, -.	F	 G1K"'F+U5	 G1V"'F+W5	 H	 I	 2'Q'H+5	 throws	 -phpDocumentor\Descriptor\Tag\ThrowsDescriptor	 2''Z+5	 5	 6 jsonLastErrorMsg9""#T;	 %3\PG\MSF\Client\ConcurrentClient::jsonLastErrorMsg()'\( )*+拿到json解析最后出现的错误信息+, -.	H	 I	 2'Q.phpDocumentor\Descriptor\Type\StringDescriptor 'H+5	 F	 5	 6  * usedTraits	 %'ConcurrentClient(\PG\MSF\Client)PG\MSF\Client*Class ConcurrentClient+," -.	package	 &phpDocumentor\Descriptor\TagDescriptor'e+c5	 
subpackage	 5	 6  * interfaces	 	 * traits	 
 * markers	 %'ConcurrentClient.php( )Default*)并行的兼容Flex标准的HTTP客户端+c不推荐使用将来可能废弃，建议使用\PG\MSF\Client\Http\Client::goConcurrent($requests), - .	author	 -phpDocumentor\Descriptor\Tag\AuthorDescriptor'o+camera360_server@camera360.com5	 	copyright	 f'r+"Chengdu pinguo Technology Co.,Ltd.5	 e	 f'e+l5	 g	 5	 6 