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