130 lines
3.4 KiB
PHP
130 lines
3.4 KiB
PHP
<?php
|
|
|
|
namespace App\Iot\Qly;
|
|
|
|
use App\Exceptions\QlyException;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Str;
|
|
|
|
/**
|
|
* 移动千里眼
|
|
*/
|
|
class HttpClient
|
|
{
|
|
const ENDPOINT_URL = 'https://open.andmu.cn';
|
|
|
|
const ENDPOINT_VERSION = '1.0.0';
|
|
|
|
protected $token;
|
|
|
|
public function __construct(
|
|
protected readonly string $appid,
|
|
protected readonly string $secret,
|
|
protected readonly string $rsa,
|
|
) {
|
|
}
|
|
|
|
public function post(string $url, array $data = [], array $headers = []): array
|
|
{
|
|
try {
|
|
return $this->request('POST', $url, [
|
|
'headers' => $headers,
|
|
'json' => $data,
|
|
]);
|
|
} catch (QlyException $e) {
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
protected function request(string $method, string $url, array $options = []): array
|
|
{
|
|
beginning:
|
|
$data = [];
|
|
if (array_key_exists('json', $options)) {
|
|
$data = $options['json'];
|
|
}
|
|
|
|
$headers = array_merge([
|
|
'Content-Type' => 'application/json',
|
|
'appid' => $this->appid,
|
|
'md5' => md5($data ? json_encode($data) : "{}"),
|
|
'timestamp' => (string) now()->getTimestampMs(),
|
|
'version' => static::ENDPOINT_VERSION,
|
|
], $options['headers'] ?? []);
|
|
|
|
if (Str::start($url, '/') === '/v3/open/api/token') {
|
|
unset($headers['token']);
|
|
} else {
|
|
$headers['token'] = isset($headers['token']) ? $headers['token'] : $this->token();
|
|
}
|
|
|
|
ksort($headers);
|
|
|
|
$headers['signature'] = $this->sign(json_encode(
|
|
Arr::only($headers, ['appid', 'md5', 'timestamp', 'token', 'version'])
|
|
));
|
|
|
|
$options['headers'] = $headers;
|
|
|
|
/** @var \Illuminate\Http\Client\Response */
|
|
$response = Http::baseUrl(static::ENDPOINT_URL)->send($method, $url, $options);
|
|
|
|
$result = $response->throw()->json();
|
|
|
|
$resultCode = data_get($result, 'resultCode', '-1');
|
|
if ($resultCode === '000000') {
|
|
return $result;
|
|
} elseif ($resultCode === '11504') {
|
|
$this->token(true);
|
|
goto beginning;
|
|
}
|
|
|
|
throw new QlyException(
|
|
data_get($result, 'resultMsg', '请求失败').', 错误码: '.$resultCode,
|
|
);
|
|
}
|
|
|
|
protected function token(bool $refresh = false): string
|
|
{
|
|
$key = "ydqly_tokens:{$this->appid}";
|
|
|
|
if (! $refresh && $this->token ??= Cache::get($key)) {
|
|
return $this->token;
|
|
}
|
|
|
|
$result = $this->post(
|
|
'/v3/open/api/token',
|
|
array_merge([
|
|
'sig' => md5($this->appid.$this->secret),
|
|
'operatorType' => 1,
|
|
]),
|
|
);
|
|
|
|
$this->token = data_get($result, 'data.token');
|
|
|
|
$ttl = (int) data_get($result, 'data.expires_in', 0) - 120;
|
|
if ($ttl > 0) {
|
|
Cache::put($key, $this->token, $ttl);
|
|
}
|
|
|
|
return $this->token;
|
|
}
|
|
|
|
/**
|
|
* 生成签名
|
|
*/
|
|
protected function sign(string $message): string
|
|
{
|
|
// rsa 私钥
|
|
$pem = "-----BEGIN PRIVATE KEY-----\n" .
|
|
wordwrap($this->rsa, 64, "\n", true) .
|
|
"\n-----END PRIVATE KEY-----";
|
|
|
|
openssl_sign($message, $signature, $pem);
|
|
|
|
return base64_encode($signature);
|
|
}
|
|
}
|