From 5e19467e8d39a16a38ff060077835e37f707f8b4 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Thu, 21 Dec 2023 16:12:38 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E5=8D=83=E9=87=8C=E7=9C=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Exceptions/QlyException.php | 9 ++ app/Http/Controllers/DeviceController.php | 21 ++++ app/Iot/Qly/HttpClient.php | 125 ++++++++++++++++++++++ config/services.php | 7 ++ database/seeders/KeywordsTableSeeder.php | 1 + 5 files changed, 163 insertions(+) create mode 100644 app/Exceptions/QlyException.php create mode 100644 app/Iot/Qly/HttpClient.php diff --git a/app/Exceptions/QlyException.php b/app/Exceptions/QlyException.php new file mode 100644 index 0000000..c48ce29 --- /dev/null +++ b/app/Exceptions/QlyException.php @@ -0,0 +1,9 @@ + 'm3u8', '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'), + ]; } // 直播地址 diff --git a/app/Iot/Qly/HttpClient.php b/app/Iot/Qly/HttpClient.php new file mode 100644 index 0000000..d6d4f14 --- /dev/null +++ b/app/Iot/Qly/HttpClient.php @@ -0,0 +1,125 @@ +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); + } +} diff --git a/config/services.php b/config/services.php index 40b812a..1983512 100644 --- a/config/services.php +++ b/config/services.php @@ -36,4 +36,11 @@ return [ 'secret' => env('LINKOS_API_SECRET'), ], + // 中国移动千里眼 + 'ydqly' => [ + 'appid' => env('YDQLY_APPID'), + 'secret' => env('YDQLY_SECRET'), + 'rsa' => env('YDQLY_RSA'), + ], + ]; diff --git a/database/seeders/KeywordsTableSeeder.php b/database/seeders/KeywordsTableSeeder.php index 1cb5914..84033cc 100644 --- a/database/seeders/KeywordsTableSeeder.php +++ b/database/seeders/KeywordsTableSeeder.php @@ -53,6 +53,7 @@ class KeywordsTableSeeder extends Seeder ['key' => 'device-supplier-linkos', 'name' => '慧联无限', 'value' => ''], ['key' => 'device-supplier-biang', 'name' => '比昂', 'value' => ''], ['key' => 'device-supplier-yunfei', 'name' => '云飞', 'value' => ''], + ['key' => 'device-supplier-ydqly', 'name' => '移动千里眼', 'value' => ''], ['key' => 'device-supplier-other', 'name' => '其它', 'value' => ''], ], ],