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  if (opts.contains("ice", Qt::CaseInsensitive))
59  return kActive;
60  return gCoreContext->GetBoolSetting("EnableMHEGic", true) ? kActive : kDisabled;
61 }
62 
63 static inline bool isCached(const QUrl& url)
64 {
65  return NetStream::GetLastModified(url).isValid();
66 }
67 
68 // Is a file ready to read?
69 bool MHInteractionChannel::CheckFile(const QString& csPath, const QByteArray &cert)
70 {
71  QUrl url(csPath);
72  QMutexLocker locker(&m_mutex);
73 
74  // Is it complete?
75  if (m_finished.contains(url))
76  return true;
77 
78  // Is it pending?
79  if (m_pending.contains(url))
80  return false; // It's pending so unavailable
81 
82  // Is it in the cache?
83  if (isCached(url))
84  return true; // It's cached
85 
86  // Queue a request
87  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("CheckFile queue %1").arg(csPath));
88  QScopedPointer< NetStream > p(new NetStream(url, NetStream::kPreferCache, cert));
89  if (!p || !p->IsOpen())
90  {
91  LOG(VB_MHEG, LOG_WARNING, LOC + QString("CheckFile failed %1").arg(csPath) );
92  return false;
93  }
94 
95  connect(p.data(), SIGNAL(Finished(QObject*)), this, SLOT(slotFinished(QObject*)) );
96  m_pending.insert(url, p.take());
97 
98  return false; // It's now pending so unavailable
99 }
100 
101 // Read a file. -1= error, 0= OK, 1= not ready
103 MHInteractionChannel::GetFile(const QString &csPath, QByteArray &data,
104  const QByteArray &cert /*=QByteArray()*/)
105 {
106  QUrl url(csPath);
107  QMutexLocker locker(&m_mutex);
108 
109  // Is it pending?
110  if (m_pending.contains(url))
111  return kPending;
112 
113  // Is it complete?
114  QScopedPointer< NetStream > p(m_finished.take(url));
115  if (p)
116  {
117  if (p->GetError() == QNetworkReply::NoError)
118  {
119  data = p->ReadAll();
120  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("GetFile finished %1").arg(csPath) );
121  return kSuccess;
122  }
123 
124  LOG(VB_MHEG, LOG_WARNING, LOC + QString("GetFile failed %1").arg(csPath) );
125  return kError;
126  }
127 
128  // Is it in the cache?
129  if (isCached(url))
130  {
131  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("GetFile cache read %1").arg(csPath) );
132 
133  locker.unlock();
134 
136  if (req.WaitTillFinished(3000) && req.GetError() == QNetworkReply::NoError)
137  {
138  data = req.ReadAll();
139  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("GetFile cache read %1 bytes %2")
140  .arg(data.size()).arg(csPath) );
141  return kSuccess;
142  }
143 
144  LOG(VB_MHEG, LOG_WARNING, LOC + QString("GetFile cache read failed %1").arg(csPath) );
145  //return kError;
146  // Retry
147  locker.relock();
148  }
149 
150  // Queue a download
151  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("GetFile queue %1").arg(csPath) );
152  p.reset(new NetStream(url, NetStream::kPreferCache, cert));
153  if (!p || !p->IsOpen())
154  {
155  LOG(VB_MHEG, LOG_WARNING, LOC + QString("GetFile failed %1").arg(csPath) );
156  return kError;
157  }
158 
159  connect(p.data(), SIGNAL(Finished(QObject*)), this, SLOT(slotFinished(QObject*)) );
160  m_pending.insert(url, p.take());
161 
162  return kPending;
163 }
164 
165 // signal from NetStream
167 {
168  NetStream* p = dynamic_cast< NetStream* >(obj);
169  if (!p)
170  return;
171 
172  QUrl url = p->Url();
173 
174  if (p->GetError() == QNetworkReply::NoError)
175  {
176  LOG(VB_MHEG, LOG_DEBUG, LOC + QString("Finished %1").arg(url.toString()) );
177  }
178  else
179  {
180  LOG(VB_MHEG, LOG_WARNING, LOC + QString("Finished %1").arg(p->GetErrorString()) );
181  }
182 
183  p->disconnect();
184 
185  QMutexLocker locker(&m_mutex);
186 
187  if (m_pending.remove(url) < 1)
188  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Finished %1 wasn't pending").arg(url.toString()) );
189  m_finished.insert(url, p);
190 }
191 
192 /* End of file */
bool CheckFile(const QString &csPath, const QByteArray &cert=QByteArray())
Definition: mhegic.cpp:69
QString GetErrorString() const
Definition: netstream.cpp:659
virtual ~MHInteractionChannel()
Definition: mhegic.cpp:33
EResult GetFile(const QString &csPath, QByteArray &data, const QByteArray &cert=QByteArray())
Definition: mhegic.cpp:103
#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:63
QByteArray ReadAll()
Definition: netstream.cpp:671
static QDateTime GetLastModified(const QUrl &url)
Definition: netstream.cpp:715
void slotFinished(QObject *)
Definition: mhegic.cpp:166
bool WaitTillFinished(unsigned long milliseconds)
Definition: netstream.cpp:636
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
static EStatus status()
Definition: mhegic.cpp:44
QNetworkReply::NetworkError GetError() const
Definition: netstream.cpp:653