MythTV  master
mhegic.cpp
Go to the documentation of this file.
1 /* MHEG Interaction Channel
2  * Copyright 2011 Lawrence Rust <lvr at softsystem dot co dot uk>
3  */
4 #include "mhegic.h"
5 
6 // Qt
7 #include <QByteArray>
8 #include <QMutexLocker>
9 #include <QNetworkRequest>
10 #include <QStringList>
11 #include <QScopedPointer>
12 #include <QApplication>
13 
14 // Myth
17 #include "netstream.h"
18 
19 #define LOC QString("[mhegic] ")
20 
21 
22 MHInteractionChannel::MHInteractionChannel(QObject* parent) : QObject(parent)
23 {
24  setObjectName("MHInteractionChannel");
25  moveToThread(&NAMThread::manager());
26 }
27 
28 // virtual
30 {
31  QMutexLocker locker(&m_mutex);
32  for (const auto & req : qAsConst(m_pending))
33  req->deleteLater();
34  for (const auto & req : qAsConst(m_finished))
35  req->deleteLater();
36 }
37 
38 // Get network status
39 // static
41 {
43  {
44  LOG(VB_MHEG, LOG_INFO, LOC + "WARN network is unavailable");
45  return kInactive;
46  }
47 
48  if (!gCoreContext->GetBoolSetting("EnableMHEG", false))
49  return kDisabled;
50 
51  QStringList opts = qEnvironmentVariable("MYTHMHEG").split(':');
52  if (opts.contains("noice", Qt::CaseInsensitive))
53  return kDisabled;
54  if (opts.contains("ice", Qt::CaseInsensitive))
55  return kActive;
56  return gCoreContext->GetBoolSetting("EnableMHEGic", true) ? kActive : kDisabled;
57 }
58 
59 static inline bool isCached(const QUrl& url)
60 {
61  return NetStream::GetLastModified(url).isValid();
62 }
63 
64 // Is a file ready to read?
65 bool MHInteractionChannel::CheckFile(const QString& csPath, const QByteArray &cert)
66 {
67  QUrl url(csPath);
68  QMutexLocker locker(&m_mutex);
69 
70  // Is it complete?
71  if (m_finished.contains(url))
72  return true;
73 
74  // Is it pending?
75  if (m_pending.contains(url))
76  return false; // It's pending so unavailable
77 
78  // Is it in the cache?
79  if (isCached(url))
80  return true; // It's cached
81 
82  // Queue a request
83  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("CheckFile queue %1").arg(csPath));
84  QScopedPointer< NetStream > p(new NetStream(url, NetStream::kPreferCache, cert));
85  if (!p || !p->IsOpen())
86  {
87  LOG(VB_MHEG, LOG_WARNING, LOC + QString("CheckFile failed %1").arg(csPath) );
88  return false;
89  }
90 
91  connect(p.data(), &NetStream::Finished, this, &MHInteractionChannel::slotFinished );
92  m_pending.insert(url, p.take());
93 
94  return false; // It's now pending so unavailable
95 }
96 
97 // Read a file. -1= error, 0= OK, 1= not ready
99 MHInteractionChannel::GetFile(const QString &csPath, QByteArray &data,
100  const QByteArray &cert /*=QByteArray()*/)
101 {
102  QUrl url(csPath);
103  QMutexLocker locker(&m_mutex);
104 
105  // Is it pending?
106  if (m_pending.contains(url))
107  return kPending;
108 
109  // Is it complete?
110  QScopedPointer< NetStream > p(m_finished.take(url));
111  if (p)
112  {
113  if (p->GetError() == QNetworkReply::NoError)
114  {
115  data = p->ReadAll();
116  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("GetFile finished %1").arg(csPath) );
117  return kSuccess;
118  }
119 
120  LOG(VB_MHEG, LOG_WARNING, LOC + QString("GetFile failed %1").arg(csPath) );
121  return kError;
122  }
123 
124  // Is it in the cache?
125  if (isCached(url))
126  {
127  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("GetFile cache read %1").arg(csPath) );
128 
129  locker.unlock();
130 
132  if (req.WaitTillFinished(3s) && req.GetError() == QNetworkReply::NoError)
133  {
134  data = req.ReadAll();
135  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("GetFile cache read %1 bytes %2")
136  .arg(data.size()).arg(csPath) );
137  return kSuccess;
138  }
139 
140  LOG(VB_MHEG, LOG_WARNING, LOC + QString("GetFile cache read failed %1").arg(csPath) );
141  //return kError;
142  // Retry
143  locker.relock();
144  }
145 
146  // Queue a download
147  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("GetFile queue %1").arg(csPath) );
148  p.reset(new NetStream(url, NetStream::kPreferCache, cert));
149  if (!p || !p->IsOpen())
150  {
151  LOG(VB_MHEG, LOG_WARNING, LOC + QString("GetFile failed %1").arg(csPath) );
152  return kError;
153  }
154 
155  connect(p.data(), &NetStream::Finished, this, &MHInteractionChannel::slotFinished );
156  m_pending.insert(url, p.take());
157 
158  return kPending;
159 }
160 
161 // signal from NetStream
163 {
164  auto* p = qobject_cast< NetStream* >(obj);
165  if (!p)
166  return;
167 
168  QUrl url = p->Url();
169 
170  if (p->GetError() == QNetworkReply::NoError)
171  {
172  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("Finished %1").arg(url.toString()) );
173  }
174  else
175  {
176  LOG(VB_MHEG, LOG_WARNING, LOC + QString("Finished %1").arg(p->GetErrorString()) );
177  }
178 
179  p->disconnect();
180 
181  QMutexLocker locker(&m_mutex);
182 
183  if (m_pending.remove(url) < 1)
184  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Finished %1 wasn't pending").arg(url.toString()) );
185  m_finished.insert(url, p);
186 }
187 
188 /* End of file */
LOC
#define LOC
Definition: mhegic.cpp:19
NetStream::ReadAll
QByteArray ReadAll()
Definition: netstream.cpp:676
MHInteractionChannel::slotFinished
void slotFinished(QObject *obj)
Definition: mhegic.cpp:162
isCached
static bool isCached(const QUrl &url)
Definition: mhegic.cpp:59
MHInteractionChannel::status
static EStatus status()
Definition: mhegic.cpp:40
MHInteractionChannel::~MHInteractionChannel
~MHInteractionChannel() override
Definition: mhegic.cpp:29
MHInteractionChannel::kError
@ kError
Definition: mhegic.h:35
NetStream::GetLastModified
static QDateTime GetLastModified(const QUrl &url)
Definition: netstream.cpp:720
MHInteractionChannel::GetFile
EResult GetFile(const QString &csPath, QByteArray &data, const QByteArray &cert=QByteArray())
Definition: mhegic.cpp:99
MHInteractionChannel::EResult
EResult
Definition: mhegic.h:35
MHInteractionChannel::m_mutex
QMutex m_mutex
Definition: mhegic.h:46
MHInteractionChannel::m_finished
map_t m_finished
Definition: mhegic.h:49
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
NetStream::WaitTillFinished
bool WaitTillFinished(std::chrono::milliseconds timeout)
Definition: netstream.cpp:641
MHInteractionChannel::kSuccess
@ kSuccess
Definition: mhegic.h:35
MHInteractionChannel::kPending
@ kPending
Definition: mhegic.h:35
netstream.h
mythlogging.h
MHInteractionChannel::EStatus
EStatus
Definition: mhegic.h:27
hardwareprofile.config.p
p
Definition: config.py:33
MHInteractionChannel::m_pending
map_t m_pending
Definition: mhegic.h:48
NetStream::Finished
void Finished(QObject *)
MHInteractionChannel::kDisabled
@ kDisabled
Definition: mhegic.h:27
NetStream
Stream content from a URI.
Definition: netstream.h:33
MHInteractionChannel::CheckFile
bool CheckFile(const QString &csPath, const QByteArray &cert=QByteArray())
Definition: mhegic.cpp:65
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
NetStream::GetError
QNetworkReply::NetworkError GetError() const
Definition: netstream.cpp:658
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:905
NetStream::isAvailable
static bool isAvailable()
Public helpers.
Definition: netstream.cpp:713
mhegic.h
mythcorecontext.h
MHInteractionChannel::MHInteractionChannel
MHInteractionChannel(QObject *parent=nullptr)
Definition: mhegic.cpp:22
NetStream::kPreferCache
@ kPreferCache
Definition: netstream.h:38
MHInteractionChannel::kActive
@ kActive
Definition: mhegic.h:27
NAMThread::manager
static NAMThread & manager()
NetworkAccessManager event loop thread.
Definition: netstream.cpp:730
MHInteractionChannel::kInactive
@ kInactive
Definition: mhegic.h:27
NetStream::kAlwaysCache
@ kAlwaysCache
Definition: netstream.h:38