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