移动千里眼

dev
Jing Li 2023-12-21 16:12:38 +08:00
parent cd90308c97
commit 5e19467e8d
5 changed files with 163 additions and 0 deletions

View File

@ -0,0 +1,9 @@
<?php
namespace App\Exceptions;
use RuntimeException;
class QlyException extends RuntimeException
{
}

View File

@ -9,6 +9,7 @@ use App\Helpers\Paginator;
use App\Http\Requestes\DeviceRequest; use App\Http\Requestes\DeviceRequest;
use App\Http\Resources\DeviceResource; use App\Http\Resources\DeviceResource;
use App\Http\Resources\WormPhotoResource; use App\Http\Resources\WormPhotoResource;
use App\Iot\Qly\HttpClient as QlyHttpClient;
use App\Models\AgriculturalBase; use App\Models\AgriculturalBase;
use App\Models\Device; use App\Models\Device;
use App\Models\InsecticidalLampDailyReport; use App\Models\InsecticidalLampDailyReport;
@ -744,6 +745,26 @@ class DeviceController extends Controller
'type' => 'm3u8', 'type' => 'm3u8',
'address' => (string) $address, 'address' => (string) $address,
]; ];
// 中国移动千里眼
case 'device-supplier-ydqly':
$client = new QlyHttpClient(
config('services.ydqly.appid'),
config('services.ydqly.secret'),
config('services.ydqly.rsa'),
);
$result = $client->post(
'/v3/open/api/websdk/player',
[
'deviceId' => $device->sn,
],
);
return [
'type' => 'iframe',
'address' => (string) data_get($result, 'data.url'),
// 'expires' => (int) data_get($result, 'data.expiresIn'),
];
} }
// 直播地址 // 直播地址

View File

@ -0,0 +1,125 @@
<?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 (YiDongException $e) {
throw $e;
}
}
protected function request(string $method, string $url, array $options = []): array
{
$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;
}
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);
}
}

View File

@ -36,4 +36,11 @@ return [
'secret' => env('LINKOS_API_SECRET'), 'secret' => env('LINKOS_API_SECRET'),
], ],
// 中国移动千里眼
'ydqly' => [
'appid' => env('YDQLY_APPID'),
'secret' => env('YDQLY_SECRET'),
'rsa' => env('YDQLY_RSA'),
],
]; ];

View File

@ -53,6 +53,7 @@ class KeywordsTableSeeder extends Seeder
['key' => 'device-supplier-linkos', 'name' => '慧联无限', 'value' => ''], ['key' => 'device-supplier-linkos', 'name' => '慧联无限', 'value' => ''],
['key' => 'device-supplier-biang', 'name' => '比昂', 'value' => ''], ['key' => 'device-supplier-biang', 'name' => '比昂', 'value' => ''],
['key' => 'device-supplier-yunfei', 'name' => '云飞', 'value' => ''], ['key' => 'device-supplier-yunfei', 'name' => '云飞', 'value' => ''],
['key' => 'device-supplier-ydqly', 'name' => '移动千里眼', 'value' => ''],
['key' => 'device-supplier-other', 'name' => '其它', 'value' => ''], ['key' => 'device-supplier-other', 'name' => '其它', 'value' => ''],
], ],
], ],