Client.php 2.8 KB
<?php


namespace lackoxygen\TopWarehouse;

use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\RequestOptions;
use Illuminate\Support\Arr;
use lackoxygen\TopWarehouse\Contracts\ClientInterface;
use lackoxygen\TopWarehouse\Contracts\RequestInterface;
use GuzzleHttp\Client as guzzleClient;
use lackoxygen\TopWarehouse\Contracts\ResponseInterface;
use lackoxygen\TopWarehouse\Exception\Exception;
use lackoxygen\TopWarehouse\Utils\SignatureUtil;

class Client implements ClientInterface
{
    protected $request;

    protected $guzzleClient;

    protected $config;

    protected function __construct(RequestInterface $request)
    {
        $this->request = $request();

        $this->config = config(TopWarehouseServiceProvider::CONFIG_NAME);

        $clientOption = \Arr::get($this->config, 'options.client', []);

        $this->guzzleClient = new guzzleClient($clientOption);
    }

    /**
     * @param RequestInterface $request
     *
     * @return ClientInterface
     */
    public static function make(RequestInterface $request): ClientInterface
    {
        return new static($request);
    }

    /**
     * @return ResponseInterface
     * @throws Exception
     */
    public function send(): ResponseInterface
    {
        $retry = Arr::get($this->config, 'options.retry', 1);

        try {
            return retry($retry, function ($attempt) {
                return $this->execute($attempt);
            }, 100, function ($exception) {
                return $exception instanceof RequestException || $exception instanceof BadResponseException;
            });
        } catch (\Throwable $exception) {
            throw new Exception($exception);
        }
    }


    /**
     * @param $attempt
     *
     * @return ResponseInterface
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function execute($attempt): ResponseInterface
    {
        $key = RequestOptions::QUERY;
        if ('GET' === strtoupper($this->request->getMethod())) {
            $key = RequestOptions::QUERY;
        } elseif ('POST' === strtoupper($this->request->getMethod())) {
            if ($this->request->getContentType() === 'application/json') {
                $key = RequestOptions::JSON;
            } else {
                $key = RequestOptions::FORM_PARAMS;
            }
        }
        $data = $this->request->toArray() + [
                'app_key'   => Arr::get($this->config, 'app_key'),
                'v'         => $this->request->getVersion(),
                'timestamp' => date('Y-m-d H:i:s'),
            ];

        $data['sign'] = SignatureUtil::generate($data, Arr::get($this->config, 'app_secret'));

        $response = $this->guzzleClient->request($this->request->getMethod(), $this->request->getPath(), [
            $key => $data
        ]);

        return new Response($response);
    }
}