• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Unionman Technology Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "StbItemWidget.h"
17 #include "MainWindow.h"
18 #include "ui_stb_item_widget.h"
19 #include <QDateTime>
20 #include <QDesktopServices>
21 #include <QDir>
22 #include <QInputDialog>
23 #include <QLineEdit>
24 #include <QMenu>
25 #include <QMessageBox>
26 #include <QMouseEvent>
27 #include <QProcess>
28 #include <QUrl>
29 
StbItemWidget(QWidget * parent)30 StbItemWidget::StbItemWidget(QWidget* parent)
31     :QWidget(parent), ui(new Ui::StbItemWidget)
32 {
33     ui->setupUi(this);
34     setLayout(ui->horizontalLayout);
35     ui->snLabel->setText("上线");
36     ui->uptimeLabel->setText("");
37     this->parent = parent;
38     setContextMenuPolicy(Qt::CustomContextMenu);
39     connect(this, &StbItemWidget::customContextMenuRequested, this, &StbItemWidget::openMenu);
40 }
41 
~StbItemWidget()42 StbItemWidget::~StbItemWidget()
43 {
44     delete ui;
45 }
46 
openConfigWeb()47 void StbItemWidget::openConfigWeb()
48 {
49     if (ip.contains(":")) {
50         QDesktopServices::openUrl(QUrl("http://[" + ip + "]"));
51     } else {
52         QDesktopServices::openUrl(QUrl("http://" + ip));
53     }
54 }
55 
playVideo()56 void StbItemWidget::playVideo()
57 {
58     qDebug() << "Ready to play video.";
59     QString urlPath = "/livestream/UM-ONVIF";
60     QString cmd = "start \"" + ip + "\"" + " .\\ffplay.exe rtsp://" + ip + urlPath
61         + " -x 1280 -y 720 -fflags nobuffer -rtsp_transport tcp";
62     system(cmd.toLatin1().data());
63 }
64 
openADBShell()65 void StbItemWidget::openADBShell()
66 {
67     QString cmd
68         = "start \"" + ip + "\" cmd /K \"hdc -t " + ip + " shell\"";
69     system(cmd.toLatin1().data());
70 }
71 
checkLog()72 void StbItemWidget::checkLog()
73 {
74     LogTextWidget* logTextWidget = new LogTextWidget(nullptr, qobject_cast<QWidget*>(this));
75     QString logTextWidgetTitle = this->sn == NULL ? "log (" + this->mac + ")" : "log (" + this->sn + ")";
76     logTextWidget->setWindowTitle(logTextWidgetTitle);
77     logTextWidget->show();
78 
79     QString logFilePath = this->getLogPath();
80 
81     this->logMutex.lock();
82     QFile file(logFilePath);
83     if (file.exists()) {
84         if (file.open(QIODevice::ReadOnly)) {
85             QString fileContent = QString(file.readAll());
86             logTextWidget->setLogText(fileContent);
87             file.close();
88         }
89     }
90     this->logMutex.unlock();
91 }
92 
openLogDirectory()93 void StbItemWidget::openLogDirectory()
94 {
95     QString localApplicationDirPath = QCoreApplication::applicationDirPath();
96 
97     QString logDir = localApplicationDirPath + "/log/" + (this->sn == NULL ? this->mac : this->sn);
98     QDir dir(logDir);
99     logDir.replace("/", QDir::separator());
100     if (!dir.exists()) {
101         if (!dir.mkpath(logDir)) {
102             QMessageBox errorBox;
103 
104             errorBox.setWindowTitle("错误");
105             errorBox.setText("日志目录不存在,且尝试创建目录失败! ");
106 
107             QFont font;
108             font.setPointSize(10L);
109             font.setWeight(QFont::Normal);
110             errorBox.setFont(font);
111 
112             errorBox.setIcon(QMessageBox::Critical);
113             errorBox.exec();
114             return;
115         }
116     }
117 
118     QUrl directoryUrl = QUrl::fromLocalFile(logDir);
119     QDesktopServices::openUrl(directoryUrl);
120 }
121 
httpRequest(QString req)122 int StbItemWidget::httpRequest(QString req)
123 {
124     QString url = "";
125     if (QHostAddress(ip).protocol() == QAbstractSocket::IPv4Protocol) {
126         url = "http://" + ip + ":6060/" + req;
127     } else if (QHostAddress(ip).protocol() == QAbstractSocket::IPv6Protocol) {
128         url = "http://[" + ip + "]:6060/" + req;
129     }
130 
131     QNetworkRequest request;
132     QNetworkAccessManager* naManager = new QNetworkAccessManager(this);
133     QMetaObject::Connection connRet
134         = QObject::connect(naManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
135     Q_ASSERT(connRet);
136 
137     qDebug() << "url: " + url;
138     request.setUrl(QUrl(url));
139 
140     QString testData = "";
141     QNetworkReply* reply = naManager->post(request, testData.toUtf8());
142     return 0;
143 }
144 
burnSN()145 void StbItemWidget::burnSN()
146 {
147     qDebug() << "Ready to burn sn.";
148     bool getInfo;
149     QInputDialog* inputDialog = new QInputDialog();
150     QString title = "修改序列号";
151     QString config = inputDialog->getText(this->parent, title, "输入序列号", QLineEdit::Normal, sn, &getInfo);
152     qDebug() << "Config: " << config << ", getInfo: " << getInfo;
153     if (getInfo) {
154         if (config.isEmpty()) {
155             config = "sn=null";
156         } else if (!config.contains("=")) {
157             config = "sn=" + config;
158         }
159 
160         httpRequest("SetDevInfo?" + config);
161     }
162 }
163 
reboot()164 void StbItemWidget::reboot()
165 {
166     QMessageBox msgBox;
167     msgBox.setWindowTitle("提示");
168     msgBox.setText("确认重启设备?");
169 
170     QFont font;
171     font.setPointSize(10L);
172     font.setWeight(QFont::Normal);
173     msgBox.setFont(font);
174 
175     msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
176     msgBox.setDefaultButton(QMessageBox::No);
177 
178     msgBox.setIcon(QMessageBox::Question);
179 
180     if (msgBox.exec() == QMessageBox::Yes) {
181         QString logInfo = "设备通过升级工具触发重启!";
182         this->writeLog(logInfo);
183         qDebug() << "Ready reboot.";
184         httpRequest("SetDevInfo?shell=reboot");
185     }
186 }
187 
enterFactoryMode()188 void StbItemWidget::enterFactoryMode()
189 {
190     QMessageBox msgBox;
191     msgBox.setWindowTitle("提示");
192     msgBox.setText("确认进入工厂模式?");
193 
194     QFont font;
195     font.setPointSize(10L);
196     font.setWeight(QFont::Normal);
197     msgBox.setFont(font);
198 
199     msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
200     msgBox.setDefaultButton(QMessageBox::No);
201 
202     msgBox.setIcon(QMessageBox::Question);
203 
204     if (msgBox.exec() == QMessageBox::Yes) {
205         QString url = "";
206         qDebug() << "Ready to enter factory.";
207         httpRequest("EnterFactoryMode");
208     }
209 }
210 
restoreFactorySetting()211 void StbItemWidget::restoreFactorySetting()
212 {
213     QMessageBox msgBox;
214     msgBox.setWindowTitle("提示");
215     msgBox.setText("确认恢复出厂设置?");
216 
217     QFont font;
218     font.setPointSize(10L);
219     font.setWeight(QFont::Normal);
220     msgBox.setFont(font);
221 
222     msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
223     msgBox.setDefaultButton(QMessageBox::No);
224 
225     msgBox.setIcon(QMessageBox::Question);
226 
227     if (msgBox.exec() == QMessageBox::Yes) {
228         QString logInfo = "设备通过升级工具触发恢复出厂设置!";
229         this->writeLog(logInfo);
230         qDebug() << "Ready to restore factory setting.";
231         httpRequest("RestoreFactorySetting");
232     }
233 }
234 
setIp(QString ip)235 void FilePusher::setIp(QString ip)
236 {
237     this->ip = ip;
238     QString title = "文件推送界面( " + this->ip + " )";
239     setWindowTitle(title);
240 }
241 
selectFile()242 void FilePusher::selectFile()
243 {
244     QString filePath = QFileDialog::getOpenFileName(this, "选择文件", "", "All Files (*)");
245     if (!filePath.isEmpty()) {
246         filePathLineEdit->setText(filePath);
247     }
248 }
249 
pushFile()250 void FilePusher::pushFile()
251 {
252     if (pushButton->text() == "推送") {
253         if (!filePathLineEdit->text().isEmpty() && !targetPathLineEdit->text().isEmpty()) {
254             m_filePusherThread.SetFilePath(filePathLineEdit->text());
255             m_filePusherThread.SetTargetPath(targetPathLineEdit->text());
256             m_filePusherThread.SetIp(ip);
257             filePathLineEdit->setEnabled(false);
258             targetPathLineEdit->setEnabled(false);
259             selectButton->setEnabled(false);
260 
261             pushButton->setText("取消");
262 
263             m_filePusherThread.start();
264         } else {
265             QMessageBox errBox;
266             QFont font;
267             font.setPointSize(10L);
268             font.setWeight(QFont::Normal);
269             errBox.setFont(font);
270             errBox.setWindowTitle("错误");
271             errBox.setText("文件路径和设备目标目录均不能为空! ");
272             errBox.setIcon(QMessageBox::Critical);
273             errBox.exec();
274         }
275     } else {
276         m_filePusherThread.CancelPush();
277 
278         filePathLineEdit->setEnabled(true);
279         targetPathLineEdit->setEnabled(true);
280         selectButton->setEnabled(true);
281 
282         pushButton->setText("推送");
283     }
284 }
285 
handlePushMessage(const QString & result)286 void FilePusher::handlePushMessage(const QString& result)
287 {
288     resultTextEdit->setPlainText(result);
289 }
290 
handlePushFinished(const QString & result)291 void FilePusher::handlePushFinished(const QString& result)
292 {
293     resultTextEdit->setPlainText(result);
294 
295     filePathLineEdit->setEnabled(true);
296     targetPathLineEdit->setEnabled(true);
297     selectButton->setEnabled(true);
298 
299     pushButton->setText("推送");
300 }
301 
CancelPush()302 void FilePusherThread::CancelPush()
303 {
304     if (pushProcess.state() == QProcess::Running) {
305         pushProcess.kill();
306     }
307     pushProcessCancal = true;
308 }
309 
Run()310 void FilePusherThread::Run()
311 {
312     QString adbPath = ".//adb//adb";
313     QStringList arguments;
314     arguments << "-s" << this->m_ip << "push" << this->m_filePath << this->m_targetPath;
315     QStringList connectArguments;
316     connectArguments << "connect" << this->m_ip;
317 
318     emit PushMessage("文件推送中...");
319 
320     pushProcess.setProgram(adbPath);
321     pushProcess.setArguments(connectArguments);
322     pushProcess.start();
323     pushProcess.waitForFinished();
324 
325     if (pushProcessCancal) {
326         emit PushMessage("文件推送已取消!");
327         pushProcessCancal = false;
328         return;
329     }
330 
331     pushProcess.setArguments(arguments);
332     pushProcess.start();
333     pushProcess.waitForFinished();
334 
335     if (pushProcessCancal) {
336         emit PushMessage("文件推送已取消!");
337         pushProcessCancal = false;
338         return;
339     }
340 
341     QByteArray output = pushProcess.readAllStandardOutput();
342     QString result = QString::fromLocal8Bit(output);
343     emit PushFinished(result);
344 }
345 
pushFile()346 void StbItemWidget::pushFile()
347 {
348     this->filePusher.setIp(this->ip);
349     filePusher.show();
350 }
351 
openMenu(const QPoint & pos)352 void StbItemWidget::openMenu(const QPoint& pos)
353 {
354     QMenu menu;
355     if (status != DEV_STATUS_OFFLINE) {
356         if (!sn.isEmpty()) {
357             connect(menu.addAction("Open Config Web"), &QAction::triggered, this, &StbItemWidget::openConfigWeb);
358         }
359 
360         connect(menu.addAction("Play Live Video"), &QAction::triggered, this, &StbItemWidget::playVideo);
361         connect(menu.addAction("Burn SN"), &QAction::triggered, this, &StbItemWidget::burnSN);
362         connect(menu.addAction("Open HDC Shell"), &QAction::triggered, this, &StbItemWidget::openADBShell);
363         connect(menu.addAction("Restore Factory Setting"), &QAction::triggered, this,
364             &StbItemWidget::restoreFactorySetting);
365         connect(menu.addAction("Push File"), &QAction::triggered, this, &StbItemWidget::pushFile);
366 
367         if (!sn.isEmpty()) {
368             connect(menu.addAction("Enter Factory Mode"), &QAction::triggered, this, &StbItemWidget::enterFactoryMode);
369         }
370 
371         connect(menu.addAction("Reboot"), &QAction::triggered, this, &StbItemWidget::reboot);
372     }
373 
374     connect(menu.addAction("Check Log"), &QAction::triggered, this, &StbItemWidget::checkLog);
375     connect(menu.addAction("Open Log Directory"), &QAction::triggered, this, &StbItemWidget::openLogDirectory);
376 
377     menu.exec(QCursor::pos());
378     qDebug() << "exit menu.";
379 }
380 
requestFinished(QNetworkReply * reply)381 void StbItemWidget::requestFinished(QNetworkReply* reply)
382 {
383     // 获取http状态码
384     QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
385     if (statusCode.isValid())
386         qDebug() << "status code=" << statusCode.toInt();
387 
388     QVariant reason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
389     if (reason.isValid())
390         qDebug() << "reason=" << reason.toString();
391 
392     QNetworkReply::NetworkError err = reply->error();
393     if (err != QNetworkReply::NoError) {
394         qDebug() << "Failed: " << reply->errorString();
395     } else {
396         // 获取返回内容
397         qDebug() << reply->readAll();
398     }
399 }
400 
mouseDoubleClickEvent(QMouseEvent * event)401 void StbItemWidget::mouseDoubleClickEvent(QMouseEvent* event)
402 {
403     if (event->button() == Qt::LeftButton) {
404         if (sn.isEmpty()) {
405             playVideo();
406         } else {
407             openConfigWeb();
408         }
409     }
410 }
411 
setIndex(int index)412 void StbItemWidget::setIndex(int index)
413 {
414     QString str = QString::asprintf("%d", index);
415     ui->indexLabel->setText(str);
416 }
417 
418 
setMainInfo(QString mac,QString sn,QString hwv,QString swv,QString dm)419 void StbItemWidget::setMainInfo(QString mac, QString sn, QString hwv, QString swv, QString dm)
420 {
421     ui->macLabel->setText(mac);
422     ui->swLabel->setText(swv);
423     ui->hwLabel->setText(hwv);
424     ui->snLabel->setText(sn);
425     ui->dmLabel->setText(dm);
426     this->mac = mac;
427     this->sn = sn;
428     this->deviceModel = dm;
429     this->hwv = hwv;
430     this->swv = swv;
431 }
432 
setIp(QString ip,bool isStatic)433 void StbItemWidget::setIp(QString ip, bool isStatic)
434 {
435     ui->ipLabel->setText(ip + (isStatic ? " (Static)" : ""));
436     this->ip = ip;
437     this->isStaticIP = isStatic;
438 }
439 
setTemperature(QString temperature)440 void StbItemWidget::setTemperature(QString temperature)
441 {
442     this->temperature = temperature;
443 }
444 
setIpcameraPss(QString ipcameraPss)445 void StbItemWidget::setIpcameraPss(QString ipcameraPss)
446 {
447     this->ipcameraPss = ipcameraPss;
448 }
449 
getLogHead()450 QString StbItemWidget::getLogHead()
451 {
452     QString file_head_str = "**************************************************************************\n"
453                             "*    Mac:\t\t\t"
454         + this->mac
455         + "\n"
456           "*    Sn:\t\t\t"
457         + this->sn
458         + "\n"
459           "*    Hardware Version:\t"
460         + this->hwv
461         + "\n"
462           "*    Software Version:\t"
463         + this->swv
464         + "\n"
465           "*    Device Model:\t\t"
466         + this->deviceModel
467         + "\n"
468           "**************************************************************************\n\n";
469     return file_head_str;
470 }
471 
logMutexLock()472 void StbItemWidget::logMutexLock()
473 {
474     this->logMutex.lock();
475 }
476 
logMutexUnlock()477 void StbItemWidget::logMutexUnlock()
478 {
479     this->logMutex.unlock();
480 }
481 
getLogPath()482 QString StbItemWidget::getLogPath()
483 {
484     QString localApplicationDirPath = QCoreApplication::applicationDirPath();
485 
486     QString logDir = localApplicationDirPath + "/log/" + (this->sn == NULL ? this->mac : this->sn);
487     QDir dir(logDir);
488     logDir.replace("/", QDir::separator());
489     if (!dir.exists()) {
490         if (!dir.mkpath(logDir)) {
491             return QString();
492         }
493     }
494 
495     QString mac = this->mac.replace(":", "-");
496     QString current_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd");
497     QString logFilePath = this->sn == NULL ? (logDir + "\\" + "log_" + current_date_time + "_" + mac + ".txt")
498                                            : (logDir + "\\" + "log_" + current_date_time + "_" + this->sn + ".txt");
499     return logFilePath;
500 }
501 
writeLog(QString info)502 void StbItemWidget::writeLog(QString info)
503 {
504     if (this->sn == NULL && this->mac == NULL) {
505         return;
506     }
507     QString logFilePath = this->getLogPath();
508 
509     QFile file(logFilePath);
510     bool file_exists = file.exists();
511     this->logMutex.lock();
512     if (file.open(QIODevice::WriteOnly | QIODevice::Append)) {
513         if (!file_exists) {
514             QString file_head_str = this->getLogHead();
515             file.write(file_head_str.toStdString().data());
516         }
517         QString current_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
518         QString log_info = "[" + current_date_time + "] " + info + "\r\n";
519         file.write(log_info.toStdString().data());
520         file.flush();
521         file.close();
522     }
523     this->logMutex.unlock();
524 }
525 
generateLogInfo()526 QString StbItemWidget::generateLogInfo()
527 {
528     qlonglong secs = (qlonglong)this->upTime.toDouble();
529     QTime time;
530     time.setHMS(0, 0, 0, 0);
531     QString timeStr = time.addSecs(int(secs)).toString("hh:mm:ss");
532     int days = secs / 24 / 60 / 60;
533     QString dt = "";
534     if (days > 0) {
535         dt += QString::number(days) + "天 ";
536     }
537     dt += timeStr;
538 
539     QString logInfo = "温度: " + this->temperature + ",  Ipcamera_PSS: " + this->ipcameraPss + ",  运行时间: " + dt;
540 
541     return logInfo;
542 }
543 
setStatusCase1()544 void StbItemWidget::setStatusCase1()
545 {
546     this->setStyleSheet("color:rgb(25, 130, 59)");
547     ui->statusLabel->setText("上线");
548     QString logInfo = "设备上线  ( 当前" + this->generateLogInfo() + " )";
549     this->writeLog(logInfo);
550 }
551 
setStatusCase2()552 void StbItemWidget::setStatusCase2()
553 {
554     this->setStyleSheet("color:rgb(223, 63, 33)");
555     ui->statusLabel->setText("离线");
556     if (this->status != DEV_STATUS_OFFLINE) {
557         QString logInfo = "设备离线  ( 最后上报" + this->generateLogInfo() + " )";
558         this->writeLog(logInfo);
559     }
560 }
561 
setStatusCase3()562 void StbItemWidget::setStatusCase3()
563 {
564     this->setStyleSheet("color:rgb(132, 112, 255)");
565     ui->statusLabel->setText("正在下载");
566     QString logInfo = "设备正在下载升级包  ( 当前" + this->generateLogInfo() + " )";
567     this->writeLog(logInfo);
568 }
569 
setStatusCase4()570 void StbItemWidget::setStatusCase4()
571 {
572     this->setStyleSheet("color:rgb(132, 112, 255)");
573     ui->statusLabel->setText("正在校验");
574     QString logInfo = "设备正在校验升级包  ( 当前" + this->generateLogInfo() + " )";
575     this->writeLog(logInfo);
576 }
577 
setStatusCase5()578 void StbItemWidget::setStatusCase5()
579 {
580     this->setStyleSheet("color:rgb(132, 112, 255)");
581     ui->statusLabel->setText("正在更新");
582     QString logInfo = "设备正在更新  ( 当前" + this->generateLogInfo() + " )";
583     this->writeLog(logInfo);
584 }
585 
setStatusCase6()586 void StbItemWidget::setStatusCase6()
587 {
588     this->setStyleSheet("color:rgb(226, 190, 27)");
589     ui->statusLabel->setText("下载失败");
590     QString logInfo = "设备下载升级包失败  ( 当前" + this->generateLogInfo() + " )";
591     this->writeLog(logInfo);
592 }
593 
setStatus(DEV_STATUS_E myStatus)594 void StbItemWidget::setStatus(DEV_STATUS_E myStatus)
595 {
596     switch (myStatus) {
597         case DEV_STATUS_IDEL: {
598             this->setStatusCase1();
599             break;
600         }
601         case DEV_STATUS_OFFLINE: {
602             this->setStatusCase2();
603             break;
604         }
605         case DEV_STATUS_UPGRADE_DOWNLOADING: {
606             this->setStatusCase3();
607             break;
608         }
609         case DEV_STATUS_UPGRADE_CHECKING: {
610             this->setStatusCase4();
611             break;
612         }
613         case DEV_STATUS_UPGRADE_UPDATING: {
614             this->setStatusCase5();
615             break;
616         }
617         case DEV_STATUS_UPGRADE_ERR_DOWNLOAD: {
618             this->setStatusCase6();
619             break;
620         }
621         case DEV_STATUS_UPGRADE_ERR_CHECK: {
622             this->setStyleSheet("color:rgb(226, 190, 27)");
623             ui->statusLabel->setText("校验失败");
624             QString logInfo = "设备升级包校验失败  ( 当前" + this->generateLogInfo() + " )";
625             this->writeLog(logInfo);
626             break;
627         }
628         case DEV_STATUS_UPGRADE_ERR_UPDATE: {
629             this->setStyleSheet("color:rgb(226, 190, 27)");
630             ;
631             ui->statusLabel->setText("升级失败");
632             QString logInfo = "设备升级失败  ( 当前" + this->generateLogInfo() + " )";
633             this->writeLog(logInfo);
634             break;
635         }
636         default: {
637             this->setStyleSheet("color:rgb(226, 190, 27)");
638             ui->statusLabel->setText("未知");
639             break;
640         }
641     }
642 
643     this->status = myStatus;
644 }
645 
getStatus()646 DEV_STATUS_E StbItemWidget::getStatus()
647 {
648     return this->status;
649 }
650 
setUptime(QString uptime)651 void StbItemWidget::setUptime(QString uptime)
652 {
653     qlonglong secs = (qlonglong)uptime.toDouble();
654     QTime time;
655     time.setHMS(0, 0, 0, 0);
656     QString timeStr = time.addSecs(int(secs)).toString("hh:mm:ss");
657     int days = secs / 24 / 60 / 60;
658     QString dt = "";
659     if (days > 0) {
660         dt += QString::number(days) + "天 ";
661     }
662     dt += timeStr;
663     ui->uptimeLabel->setText(dt);
664 
665     if (uptime.toDouble() < this->upTime.toDouble()) {
666         QString logInfo = " 设备重启! ";
667         this->writeLog(logInfo);
668     }
669     this->upTime = uptime;
670 }
671