00001 #include <qdir.h>
00002 #include <qfileinfo.h>
00003 #include <qstring.h>
00004 #include <qstringlist.h>
00005
00006 #include <mythtv/mythcontext.h>
00007 #include <mythtv/mythdbcon.h>
00008
00009 #include "weatherScreen.h"
00010 #include "weatherSource.h"
00011 #include "sourceManager.h"
00012
00013 #define LOC QString("SourceManager: ")
00014 #define LOC_ERR QString("SourceManager Error: ")
00015
00016 SourceManager::SourceManager()
00017 {
00018 findScriptsDB();
00019 setupSources();
00020 m_scripts.setAutoDelete(true);
00021 m_sources.setAutoDelete(true);
00022 }
00023
00024 bool SourceManager::findScriptsDB()
00025 {
00026 MSqlQuery db(MSqlQuery::InitCon());
00027 QString query =
00028 "SELECT DISTINCT wss.sourceid, source_name, update_timeout, "
00029 "retrieve_timeout, path, author, version, email, types "
00030 "FROM weathersourcesettings wss "
00031 "LEFT JOIN weatherdatalayout wdl "
00032 "ON wss.sourceid = wdl.weathersourcesettings_sourceid "
00033 "WHERE hostname = :HOST;";
00034
00035 db.prepare(query);
00036 db.bindValue(":HOST", gContext->GetHostName());
00037 if (!db.exec())
00038 {
00039 VERBOSE(VB_IMPORTANT, db.lastError().text());
00040 return false;
00041 }
00042
00043 while (db.next())
00044 {
00045 QFileInfo *fi = new QFileInfo(db.value(4).toString());
00046
00047 if (!fi->isExecutable())
00048 {
00049
00050
00051 delete fi;
00052 continue;
00053 }
00054 ScriptInfo *si = new ScriptInfo;
00055 si->id = db.value(0).toInt();
00056 si->name = db.value(1).toString();
00057 si->updateTimeout = db.value(2).toUInt() * 1000;
00058 si->scriptTimeout = db.value(3).toUInt() * 1000;
00059 si->file = fi;
00060 si->author = db.value(5).toString();
00061 si->version = db.value(6).toString();
00062 si->email = db.value(7).toString();
00063 si->types = QStringList::split(",", db.value(8).toString());
00064 m_scripts.append(si);
00065 }
00066
00067 return true;
00068 }
00069
00070 bool SourceManager::findScripts()
00071 {
00072 QString path = gContext->GetShareDir() + "mythweather/scripts/";
00073 QDir dir(path);
00074 dir.setFilter(QDir::Executable | QDir::Files | QDir::Dirs);
00075
00076 MythBusyDialog *busyd = new MythBusyDialog(
00077 QObject::tr("Searching for scripts"));
00078
00079
00080 if (!dir.exists())
00081 {
00082 VERBOSE(VB_IMPORTANT, "MythWeather: Scripts directory not found");
00083 return false;
00084 }
00085
00086 recurseDirs(dir);
00087
00088
00089 MSqlQuery db(MSqlQuery::InitCon());
00090
00091 db.prepare("SELECT sourceid, path FROM weathersourcesettings "
00092 "WHERE hostname = :HOST;");
00093 db.bindValue(":HOST", gContext->GetHostName());
00094 db.exec();
00095 QStringList toRemove;
00096 while (db.next())
00097 {
00098 QFileInfo fi(db.value(1).toString());
00099 if (!fi.isExecutable())
00100 {
00101 toRemove << db.value(0).toString();
00102 VERBOSE(VB_GENERAL, fi.absFilePath() + " No longer exists");
00103 }
00104 }
00105
00106 db.prepare("DELETE FROM weathersourcesettings WHERE sourceid = :ID;");
00107 for (uint i = 0; i < toRemove.count(); ++i)
00108 {
00109 db.bindValue(":ID", toRemove[i]);
00110 if (!db.exec())
00111 {
00112 VERBOSE(VB_IMPORTANT, db.lastError().text());
00113 }
00114 }
00115
00116 busyd->Close();
00117 busyd->deleteLater();
00118
00119 return m_scripts.count() > 0;
00120 }
00121
00122 void SourceManager::clearSources()
00123 {
00124 m_scripts.clear();
00125 m_sources.clear();
00126 }
00127
00128 void SourceManager::setupSources()
00129 {
00130 MSqlQuery db(MSqlQuery::InitCon());
00131
00132 QString query = "SELECT DISTINCT location,weathersourcesettings_sourceid,weatherscreens.units,"
00133 "weatherscreens.screen_id FROM weatherdatalayout,weatherscreens "
00134 "WHERE weatherscreens.screen_id = weatherscreens_screen_id AND weatherscreens.hostname = :HOST;";
00135 db.prepare(query);
00136 db.bindValue(":HOST", gContext->GetHostName());
00137 if (!db.exec())
00138 {
00139 VERBOSE(VB_IMPORTANT, db.lastError().text());
00140 return;
00141 }
00142
00143 m_sourcemap.clear();
00144
00145 while (db.next())
00146 {
00147 QString loc = db.value(0).toString();
00148 uint sourceid = db.value(1).toUInt();
00149 units_t units = db.value(2).toUInt();
00150 uint screen = db.value(3).toUInt();
00151 const WeatherSource *src = needSourceFor(sourceid, loc, units);
00152 m_sourcemap.insert((long)screen, src);
00153 }
00154 }
00155
00156 ScriptInfo *SourceManager::getSourceByName(const QString &name)
00157 {
00158 ScriptInfo *src = 0;
00159 for (src = m_scripts.first(); src; src = m_scripts.next())
00160 {
00161 if (src->name == name)
00162 {
00163 return src;
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 }
00175 }
00176
00177 if (!src)
00178 {
00179 VERBOSE(VB_IMPORTANT, "No Source found for " + name);
00180 }
00181
00182 return NULL;
00183 }
00184
00185 QStringList SourceManager::getLocationList(ScriptInfo *si, const QString &str)
00186 {
00187 if (!m_scripts.contains(si))
00188 return NULL;
00189 WeatherSource *ws = new WeatherSource(si);
00190 return ws->getLocationList(str);
00191 }
00192
00193 WeatherSource *SourceManager::needSourceFor(int id, const QString &loc,
00194 units_t units)
00195 {
00196
00197 WeatherSource *src;
00198 for (src = m_sources.first(); src; src = m_sources.next())
00199 {
00200 if (src->getId() == id && src->getLocale() == loc &&
00201 src->getUnits() == units)
00202 {
00203 return src;
00204 }
00205 }
00206
00207
00208 ScriptInfo *si;
00209 for (si = m_scripts.first(); si; si = m_scripts.next())
00210 {
00211 if (si->id == id)
00212 {
00213 WeatherSource *ws = new WeatherSource(si);
00214 ws->setLocale(loc);
00215 ws->setUnits(units);
00216 m_sources.append(ws);
00217 return ws;
00218 }
00219 }
00220
00221 VERBOSE(VB_IMPORTANT, LOC + QString("NeedSourceFor: Unable to find source "
00222 "for %1, %2, %3").arg(id).arg(loc).arg(units));
00223 return NULL;
00224 }
00225
00226 void SourceManager::startTimers()
00227 {
00228 WeatherSource *src;
00229 for (src = m_sources.first(); src; src = m_sources.next())
00230 src->startUpdateTimer();
00231 }
00232
00233 void SourceManager::stopTimers()
00234 {
00235 WeatherSource *src;
00236 for (src = m_sources.first(); src; src = m_sources.next())
00237 src->stopUpdateTimer();
00238 }
00239
00240 void SourceManager::doUpdate()
00241 {
00242 WeatherSource *src;
00243 for (src = m_sources.first(); src; src = m_sources.next())
00244 {
00245 if (src->isRunning())
00246 {
00247 VERBOSE(VB_GENERAL, tr("Script %1 is still running when trying to do update, "
00248 "Make sure it isn't hanging, make sure timeout values are sane... "
00249 "Not running this time around").arg(src->getName()));
00250 }
00251 else if (src->inUse())
00252 src->startUpdate();
00253 }
00254 }
00255
00256 bool SourceManager::findPossibleSources(QStringList types,
00257 QPtrList<ScriptInfo> &sources)
00258 {
00259 ScriptInfo *si;
00260 QPtrList<ScriptInfo> results;
00261 bool handled;
00262 for (si = m_scripts.first(); si; si = m_scripts.next())
00263 {
00264 QStringList stypes = si->types;
00265 handled = true;
00266 uint i;
00267 for (i = 0; i < types.count() && handled; ++i)
00268 {
00269 handled = stypes.contains(types[i]);
00270 }
00271 if (handled)
00272 results.append(si);
00273 }
00274
00275 if (results.count())
00276 {
00277 sources = results;
00278 return true;
00279 }
00280 else
00281 return false;
00282 }
00283
00284 bool SourceManager::connectScreen(uint id, WeatherScreen *screen)
00285 {
00286 if (!screen)
00287 {
00288 VERBOSE(VB_IMPORTANT, LOC_ERR +
00289 "Can not connect nonexistent screen "<<screen);
00290
00291 return false;
00292 }
00293
00294 WeatherSource *ws = m_sourcemap[id];
00295 if (!ws)
00296 {
00297 VERBOSE(VB_IMPORTANT, LOC_ERR +
00298 "Can not connect nonexistent source "<<id);
00299
00300 return false;
00301 }
00302 ws->connectScreen(screen);
00303 return true;
00304 }
00305
00306 bool SourceManager::disconnectScreen(WeatherScreen *screen)
00307 {
00308 if (!screen)
00309 {
00310 VERBOSE(VB_IMPORTANT, LOC_ERR +
00311 "Can not disconnect nonexistent screen "<<screen);
00312
00313 return false;
00314 }
00315
00316 WeatherSource *ws = m_sourcemap[screen->getId()];
00317 if (!ws)
00318 {
00319 VERBOSE(VB_IMPORTANT, LOC_ERR +
00320 "Can not disconnect nonexistent source "<<screen->getId());
00321
00322 return false;
00323 }
00324 ws->disconnectScreen(screen);
00325 return true;
00326 }
00327
00328
00329 void SourceManager::recurseDirs( QDir dir )
00330 {
00331 if (!dir.exists())
00332 return;
00333
00334 dir.setFilter(QDir::Executable | QDir::Files | QDir::Dirs);
00335 const QFileInfoList *files = dir.entryInfoList();
00336 if (!files)
00337 return;
00338
00339 QFileInfoListIterator itr(*files);
00340 QFileInfo *file;
00341
00342 while ((file = itr.current()))
00343 {
00344 ++itr;
00345 if (file->isDir())
00346 {
00347 if (file->fileName() == QString("..")) continue;
00348 if (file->fileName() == QString(".")) continue;
00349 QDir recurseTo(file->filePath());
00350 recurseDirs(recurseTo);
00351 }
00352
00353 if (file->isExecutable() && !(file->isDir()))
00354 {
00355 ScriptInfo *info = WeatherSource::probeScript(*file);
00356 if (info)
00357 {
00358 m_scripts.append(info);
00359 VERBOSE(VB_GENERAL, "found script " + file->absFilePath());
00360 }
00361 }
00362 }
00363
00364 return;
00365 }