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
21MHInteractionChannel::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
58static inline bool isCached(const QUrl& url)
59{
60 return NetStream::GetLastModified(url).isValid();
61}
62
63// Is a file ready to read?
64bool 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
98MHInteractionChannel::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
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 */
EResult GetFile(const QString &csPath, QByteArray &data, const QByteArray &cert=QByteArray())
Definition: mhegic.cpp:98
bool CheckFile(const QString &csPath, const QByteArray &cert=QByteArray())
Definition: mhegic.cpp:64
static EStatus status()
Definition: mhegic.cpp:39
void slotFinished(QObject *obj)
Definition: mhegic.cpp:161
~MHInteractionChannel() override
Definition: mhegic.cpp:28
MHInteractionChannel(QObject *parent=nullptr)
Definition: mhegic.cpp:21
bool GetBoolSetting(const QString &key, bool defaultval=false)
static NAMThread & manager()
NetworkAccessManager event loop thread.
Definition: netstream.cpp:745
Stream content from a URI.
Definition: netstream.h:32
static bool isAvailable()
Public helpers.
Definition: netstream.cpp:728
@ kPreferCache
Definition: netstream.h:36
@ kAlwaysCache
Definition: netstream.h:36
QByteArray ReadAll()
Definition: netstream.cpp:691
QNetworkReply::NetworkError GetError() const
Definition: netstream.cpp:673
static QDateTime GetLastModified(const QUrl &url)
Definition: netstream.cpp:735
void Finished(QObject *)
bool WaitTillFinished(std::chrono::milliseconds timeout)
Definition: netstream.cpp:656
#define LOC
Definition: mhegic.cpp:18
static bool isCached(const QUrl &url)
Definition: mhegic.cpp:58
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39