MythTV  master
mythbackend_main_helpers.cpp
Go to the documentation of this file.
1 #include "libmythbase/mythconfig.h"
2 #if CONFIG_SYSTEMD_NOTIFY
3 #include <systemd/sd-daemon.h>
4 static inline void be_sd_notify(const char *str) { sd_notify(0, str); };
5 #else
6 static inline void be_sd_notify(const char */*str*/) {};
7 #endif
8 
9 // C++ headers
10 #include <cerrno>
11 #include <csignal>
12 #include <cstdlib>
13 #include <fcntl.h>
14 #include <sys/stat.h>
15 #include <sys/time.h> // for setpriority
16 #include <sys/types.h>
17 #include <unistd.h>
18 
19 // Qt
20 #include <QCoreApplication>
21 #include <QFileInfo>
22 #include <QFile>
23 #include <QDir>
24 #include <QMap>
25 
26 // MythTV
27 #include "libmyth/mythcontext.h"
28 #include "libmythbase/compat.h"
29 #include "libmythbase/dbutil.h"
30 #include "libmythbase/exitcodes.h"
32 #include "libmythbase/mythdb.h"
36 #include "libmythbase/mythversion.h"
38 #include "libmythbase/remoteutil.h"
41 #include "libmythtv/dbcheck.h"
42 #include "libmythtv/eitcache.h"
43 #include "libmythtv/jobqueue.h"
47 #include "libmythtv/tv_rec.h"
48 
49 // MythBackend
50 #include "autoexpire.h"
51 #include "backendcontext.h"
52 #include "backendhousekeeper.h"
53 #include "encoderlink.h"
54 #include "httpstatus.h"
55 #include "mainserver.h"
56 #include "mediaserver.h"
59 #include "scheduler.h"
60 
61 // New webserver
65 #include "servicesv2/v2myth.h"
66 #include "servicesv2/v2video.h"
67 #include "servicesv2/v2dvr.h"
68 #include "servicesv2/v2content.h"
69 #include "servicesv2/v2guide.h"
70 #include "servicesv2/v2channel.h"
71 #include "servicesv2/v2status.h"
72 #include "servicesv2/v2capture.h"
73 #include "servicesv2/v2music.h"
74 #include "servicesv2/v2config.h"
75 
76 #define LOC QString("MythBackend: ")
77 #define LOC_WARN QString("MythBackend, Warning: ")
78 #define LOC_ERR QString("MythBackend, Error: ")
79 
80 static HouseKeeper *gHousekeeping { nullptr };
81 static JobQueue *gJobQueue { nullptr };
83 static MediaServer *g_pUPnp { nullptr };
84 static MainServer *mainServer { nullptr };
85 static QString gPidFile;
86 
87 bool setupTVs(bool ismaster, bool &error)
88 {
89  error = false;
90  QString localhostname = gCoreContext->GetHostName();
91 
93 
94  if (ismaster)
95  {
96  // Hack to make sure recorded.basename gets set if the user
97  // downgrades to a prior version and creates new entries
98  // without it.
99  if (!query.exec("UPDATE recorded SET basename = CONCAT(chanid, '_', "
100  "DATE_FORMAT(starttime, '%Y%m%d%H%i00'), '_', "
101  "DATE_FORMAT(endtime, '%Y%m%d%H%i00'), '.nuv') "
102  "WHERE basename = '';"))
103  MythDB::DBError("Updating record basename", query);
104 
105  // Hack to make sure record.station gets set if the user
106  // downgrades to a prior version and creates new entries
107  // without it.
108  if (!query.exec("UPDATE channel SET callsign=chanid "
109  "WHERE callsign IS NULL OR callsign='';"))
110  MythDB::DBError("Updating channel callsign", query);
111 
112  if (query.exec("SELECT MIN(chanid) FROM channel;"))
113  {
114  query.first();
115  int min_chanid = query.value(0).toInt();
116  if (!query.exec(QString("UPDATE record SET chanid = %1 "
117  "WHERE chanid IS NULL;").arg(min_chanid)))
118  MythDB::DBError("Updating record chanid", query);
119  }
120  else
121  MythDB::DBError("Querying minimum chanid", query);
122 
123  MSqlQuery records_without_station(MSqlQuery::InitCon());
124  records_without_station.prepare("SELECT record.chanid,"
125  " channel.callsign FROM record LEFT JOIN channel"
126  " ON record.chanid = channel.chanid WHERE record.station='';");
127  if (records_without_station.exec() && records_without_station.next())
128  {
129  MSqlQuery update_record(MSqlQuery::InitCon());
130  update_record.prepare("UPDATE record SET station = :CALLSIGN"
131  " WHERE chanid = :CHANID;");
132  do
133  {
134  update_record.bindValue(":CALLSIGN",
135  records_without_station.value(1));
136  update_record.bindValue(":CHANID",
137  records_without_station.value(0));
138  if (!update_record.exec())
139  {
140  MythDB::DBError("Updating record station", update_record);
141  }
142  } while (records_without_station.next());
143  }
144  }
145 
146  if (!query.exec(
147  "SELECT cardid, parentid, videodevice, hostname, sourceid "
148  "FROM capturecard "
149  "ORDER BY cardid"))
150  {
151  MythDB::DBError("Querying Recorders", query);
152  return false;
153  }
154 
155  std::vector<unsigned int> cardids;
156  std::vector<QString> hosts;
157  while (query.next())
158  {
159  uint cardid = query.value(0).toUInt();
160  uint parentid = query.value(1).toUInt();
161  QString videodevice = query.value(2).toString();
162  QString hostname = query.value(3).toString();
163  uint sourceid = query.value(4).toUInt();
164  QString cidmsg = QString("Card[%1](%2)").arg(cardid).arg(videodevice);
165 
166  if (hostname.isEmpty())
167  {
168  LOG(VB_GENERAL, LOG_ERR, cidmsg +
169  " does not have a hostname defined.\n"
170  "Please run setup and confirm all of the capture cards.\n");
171  continue;
172  }
173 
174  // Skip all cards that do not have a video source
175  if (sourceid == 0)
176  {
177  if (parentid == 0)
178  {
179  LOG(VB_GENERAL, LOG_WARNING, cidmsg +
180  " does not have a video source");
181  }
182  continue;
183  }
184 
185  cardids.push_back(cardid);
186  hosts.push_back(hostname);
187  }
188 
189  QWriteLocker tvlocker(&TVRec::s_inputsLock);
190 
191  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
192  for (size_t i = 0; i < cardids.size(); i++)
193  {
194  if (hosts[i] == localhostname) {
195  // No memory leak. The constructor for TVRec adds the item
196  // to the static map TVRec::s_inputs.
197  new TVRec(cardids[i]);
198  }
199  }
200 
201  for (size_t i = 0; i < cardids.size(); i++)
202  {
203  uint cardid = cardids[i];
204  QString host = hosts[i];
205  QString cidmsg = QString("Card %1").arg(cardid);
206 
207  if (!ismaster)
208  {
209  if (host == localhostname)
210  {
211  TVRec *tv = TVRec::GetTVRec(cardid);
212  if (tv && tv->Init())
213  {
214  auto *enc = new EncoderLink(cardid, tv);
215  gTVList[cardid] = enc;
216  }
217  else
218  {
219  LOG(VB_GENERAL, LOG_ERR, "Problem with capture cards. " +
220  cidmsg + " failed init");
221  delete tv;
222  // No longer set an error here, because we need the
223  // slave backend to be able to start without a capture
224  // card, so that it can be setup through the web app
225  }
226  }
227  }
228  else
229  {
230  if (host == localhostname)
231  {
232  TVRec *tv = TVRec::GetTVRec(cardid);
233  if (tv && tv->Init())
234  {
235  auto *enc = new EncoderLink(cardid, tv);
236  gTVList[cardid] = enc;
237  }
238  else
239  {
240  LOG(VB_GENERAL, LOG_ERR, "Problem with capture cards. " +
241  cidmsg + " failed init");
242  delete tv;
243  }
244  }
245  else
246  {
247  auto *enc = new EncoderLink(cardid, nullptr, host);
248  gTVList[cardid] = enc;
249  }
250  }
251  }
252 
253  if (gTVList.empty())
254  {
255  LOG(VB_GENERAL, LOG_WARNING, LOC +
256  "No valid capture cards are defined in the database.");
257  }
258 
259  return true;
260 }
261 
262 void cleanup(void)
263 {
264  if (mainServer)
265  {
266  mainServer->Stop();
267  qApp->processEvents();
268  }
269 
270  if (gCoreContext)
272 
273  delete gSysEventHandler;
274  gSysEventHandler = nullptr;
275 
276  delete gHousekeeping;
277  gHousekeeping = nullptr;
278 
279  if (gCoreContext)
280  {
281  delete gCoreContext->GetScheduler();
282  gCoreContext->SetScheduler(nullptr);
283  }
284 
285  delete gExpirer;
286  gExpirer = nullptr;
287 
288  delete gJobQueue;
289  gJobQueue = nullptr;
290 
291  delete g_pUPnp;
292  g_pUPnp = nullptr;
293 
294  if (SSDP::Instance())
295  {
297  SSDP::Instance()->wait();
298  }
299 
300  if (TaskQueue::Instance())
301  {
304  }
305 
306  while (!TVRec::s_inputs.empty())
307  {
308  TVRec *rec = *TVRec::s_inputs.begin();
309  delete rec;
310  }
311 
312 
313  delete gContext;
314  gContext = nullptr;
315 
316  delete mainServer;
317  mainServer = nullptr;
318 
319  delete gBackendContext;
320  gBackendContext = nullptr;
321 
322  if (!gPidFile.isEmpty())
323  {
324  QFile::remove(gPidFile);
325  gPidFile.clear();
326  }
327 
329 }
330 
332 {
333  if (cmdline.toBool("setverbose"))
334  {
336  {
337  QString message = "SET_VERBOSE ";
338  message += cmdline.toString("setverbose");
339 
340  gCoreContext->SendMessage(message);
341  LOG(VB_GENERAL, LOG_INFO,
342  QString("Sent '%1' message").arg(message));
343  return GENERIC_EXIT_OK;
344  }
345  LOG(VB_GENERAL, LOG_ERR,
346  "Unable to connect to backend, verbose mask unchanged ");
348  }
349 
350  if (cmdline.toBool("setloglevel"))
351  {
353  {
354  QString message = "SET_LOG_LEVEL ";
355  message += cmdline.toString("setloglevel");
356 
357  gCoreContext->SendMessage(message);
358  LOG(VB_GENERAL, LOG_INFO,
359  QString("Sent '%1' message").arg(message));
360  return GENERIC_EXIT_OK;
361  }
362  LOG(VB_GENERAL, LOG_ERR,
363  "Unable to connect to backend, log level unchanged ");
365  }
366 
367  if (cmdline.toBool("printsched") ||
368  cmdline.toBool("testsched"))
369  {
370  auto *sched = new Scheduler(false, &gTVList);
371  if (cmdline.toBool("printsched"))
372  {
374  {
375  LOG(VB_GENERAL, LOG_ERR, "Cannot connect to master");
376  delete sched;
378  }
379  std::cout << "Retrieving Schedule from Master backend.\n";
381  }
382  else
383  {
384  std::cout << "Calculating Schedule from database.\n" <<
385  "Inputs, Card IDs, and Conflict info may be invalid "
386  "if you have multiple tuners.\n";
389  }
390 
391  verboseMask |= VB_SCHEDULE;
392  LogLevel_t oldLogLevel = logLevel;
393  logLevel = LOG_DEBUG;
394  sched->PrintList(true);
395  logLevel = oldLogLevel;
396  delete sched;
397  return GENERIC_EXIT_OK;
398  }
399 
400  if (cmdline.toBool("printexpire"))
401  {
402  gExpirer = new AutoExpire();
403  gExpirer->PrintExpireList(cmdline.toString("printexpire"));
404  return GENERIC_EXIT_OK;
405  }
406 
407  // This should never actually be reached..
408  return GENERIC_EXIT_OK;
409 }
410 using namespace MythTZ;
411 
413 {
414  auto *tempMonitorConnection = new MythSocket();
415  if (tempMonitorConnection->ConnectToHost(
418  {
419  if (!gCoreContext->CheckProtoVersion(tempMonitorConnection))
420  {
421  LOG(VB_GENERAL, LOG_ERR, "Master backend is incompatible with "
422  "this backend.\nCannot become a slave.");
423  tempMonitorConnection->DecrRef();
425  }
426 
427  QStringList tempMonitorDone("DONE");
428 
429  QStringList tempMonitorAnnounce(QString("ANN Monitor %1 0")
430  .arg(gCoreContext->GetHostName()));
431  tempMonitorConnection->SendReceiveStringList(tempMonitorAnnounce);
432  if (tempMonitorAnnounce.empty() ||
433  tempMonitorAnnounce[0] == "ERROR")
434  {
435  tempMonitorConnection->DecrRef();
436  tempMonitorConnection = nullptr;
437  if (tempMonitorAnnounce.empty())
438  {
439  LOG(VB_GENERAL, LOG_ERR, LOC +
440  "Failed to open event socket, timeout");
441  }
442  else
443  {
444  LOG(VB_GENERAL, LOG_ERR, LOC +
445  "Failed to open event socket" +
446  ((tempMonitorAnnounce.size() >= 2) ?
447  QString(", error was %1").arg(tempMonitorAnnounce[1]) :
448  QString(", remote error")));
449  }
450  }
451 
452  QStringList timeCheck;
453  if (tempMonitorConnection)
454  {
455  timeCheck.push_back("QUERY_TIME_ZONE");
456  tempMonitorConnection->SendReceiveStringList(timeCheck);
457  tempMonitorConnection->WriteStringList(tempMonitorDone);
458  }
459  if (timeCheck.size() < 3)
460  {
461  if (tempMonitorConnection)
462  tempMonitorConnection->DecrRef();
464  }
465 
466  QDateTime our_time = MythDate::current();
467  QDateTime master_time = MythDate::fromString(timeCheck[2]);
468  int timediff = abs(our_time.secsTo(master_time));
469 
470  if (timediff > 300)
471  {
472  LOG(VB_GENERAL, LOG_ERR,
473  QString("Current time on the master backend differs by "
474  "%1 seconds from time on this system. Exiting.")
475  .arg(timediff));
476  if (tempMonitorConnection)
477  tempMonitorConnection->DecrRef();
479  }
480 
481  if (timediff > 20)
482  {
483  LOG(VB_GENERAL, LOG_WARNING,
484  QString("Time difference between the master "
485  "backend and this system is %1 seconds.")
486  .arg(timediff));
487  }
488  }
489  if (tempMonitorConnection)
490  tempMonitorConnection->DecrRef();
491 
492  return GENERIC_EXIT_OK;
493 }
494 
495 
497 {
498  if (cmdline.toBool("nohousekeeper"))
499  {
500  LOG(VB_GENERAL, LOG_WARNING, LOC +
501  "****** The Housekeeper has been DISABLED with "
502  "the --nohousekeeper option ******");
503  }
504  if (cmdline.toBool("nosched"))
505  {
506  LOG(VB_GENERAL, LOG_WARNING, LOC +
507  "********** The Scheduler has been DISABLED with "
508  "the --nosched option **********");
509  }
510  if (cmdline.toBool("noautoexpire"))
511  {
512  LOG(VB_GENERAL, LOG_WARNING, LOC +
513  "********* Auto-Expire has been DISABLED with "
514  "the --noautoexpire option ********");
515  }
516  if (cmdline.toBool("nojobqueue"))
517  {
518  LOG(VB_GENERAL, LOG_WARNING, LOC +
519  "********* The JobQueue has been DISABLED with "
520  "the --nojobqueue option *********");
521  }
522 }
523 
525 {
526  gPidFile = cmdline.toString("pidfile");
527  if (!gPidFile.isEmpty())
528  {
529  QFile file(gPidFile);
530  if (file.open(QIODevice::WriteOnly))
531  {
532  qint64 pid = QCoreApplication::applicationPid();
533  file.write(qPrintable(QString("%1\n").arg(pid)));
534  file.close();
535  }
536  else
537  {
538  LOG(VB_GENERAL, LOG_WARNING,
539  QString(LOC + "Cannot open pidfile named %1").arg(gPidFile));
540  }
541  }
542 
544 
546  {
547  return run_setup_webserver();
548  }
550  {
551  LOG(VB_GENERAL, LOG_ERR,
552  "MySQL time zone support is missing. "
553  "Please install it and try again. "
554  "See 'mysql_tzinfo_to_sql' for assistance.");
555  gCoreContext->GetDB()->IgnoreDatabase(true);
557  return run_setup_webserver();
558  }
559  bool ismaster = gCoreContext->IsMasterHost();
560 
561  if (!UpgradeTVDatabaseSchema(ismaster, ismaster, true))
562  {
563  LOG(VB_GENERAL, LOG_ERR,
564  QString("Couldn't upgrade database to new schema on %1 backend.")
565  .arg(ismaster ? "master" : "slave"));
567  return run_setup_webserver();
568  }
569 
570  be_sd_notify("STATUS=Loading translation");
571  MythTranslation::load("mythfrontend");
572 
573  if (cmdline.toBool("webonly"))
574  {
576  return run_setup_webserver();
577  }
578  if (!ismaster)
579  {
580  be_sd_notify("STATUS=Connecting to master backend");
581  int ret = connect_to_master();
582  if (ret != GENERIC_EXIT_OK)
583  return ret;
584  }
585 
586  be_sd_notify("STATUS=Get backend server port");
587  int port = gCoreContext->GetBackendServerPort();
588  if (gCoreContext->GetBackendServerIP().isEmpty())
589  {
590  std::cerr << "No setting found for this machine's BackendServerAddr.\n"
591  << "MythBackend starting in Web App only mode for initial setup.\n"
592  << "Use http://<yourBackend>:6544 to perform setup.\n";
594  return run_setup_webserver();
595  }
596 
598 
599  if (ismaster)
600  {
601  LOG(VB_GENERAL, LOG_NOTICE, LOC + "Starting up as the master server.");
602  }
603  else
604  {
605  LOG(VB_GENERAL, LOG_NOTICE, LOC + "Running as a slave backend.");
606  }
607 
608  if (ismaster)
609  {
611  }
612 
614 
615  bool fatal_error = false;
616  bool runsched = setupTVs(ismaster, fatal_error);
617  if (fatal_error)
619 
620  Scheduler *sched = nullptr;
621  if (ismaster)
622  {
623  if (runsched)
624  {
625  be_sd_notify("STATUS=Creating scheduler");
626  sched = new Scheduler(true, &gTVList);
627  int err = sched->GetError();
628  if (err)
629  {
630  delete sched;
631  return err;
632  }
633 
634  if (cmdline.toBool("nosched"))
636  }
637 
638  if (!cmdline.toBool("noautoexpire"))
639  {
640  gExpirer = new AutoExpire(&gTVList);
641  if (sched)
643  }
646  }
647 
648  if (!cmdline.toBool("nohousekeeper"))
649  {
650  be_sd_notify("STATUS=Creating housekeeper");
651  gHousekeeping = new HouseKeeper();
652 
653  if (ismaster)
654  {
659 
660  // only run this task if MythMusic is installed and we have a new enough schema
661  if (gCoreContext->GetNumSetting("MusicDBSchemaVer", 0) >= 1024)
663  }
664 
666 #ifdef __linux__
667  #ifdef CONFIG_BINDINGS_PYTHON
669  #endif
670 #endif
671 
672  gHousekeeping->Start();
673  }
674 
675  if (!cmdline.toBool("nojobqueue"))
676  gJobQueue = new JobQueue(ismaster);
677 
678  // ----------------------------------------------------------------------
679  //
680  // ----------------------------------------------------------------------
681 
682  if (g_pUPnp == nullptr)
683  {
684  be_sd_notify("STATUS=Creating UPnP media server");
685  g_pUPnp = new MediaServer();
686 
687  g_pUPnp->Init(ismaster, cmdline.toBool("noupnp"));
688  }
689 
690  if (cmdline.toBool("dvbv3"))
691  {
692  LOG(VB_GENERAL, LOG_INFO, LOC + "Use legacy DVBv3 API");
693  gCoreContext->SetDVBv3(true);
694  }
695 
696  // ----------------------------------------------------------------------
697  // Setup status server
698  // ----------------------------------------------------------------------
699 
700  HttpStatus *httpStatus = nullptr;
701  HttpServer *pHS = g_pUPnp->GetHttpServer();
702 
703  if (pHS)
704  {
705  LOG(VB_GENERAL, LOG_INFO, "Main::Registering HttpStatus Extension");
706  be_sd_notify("STATUS=Registering HttpStatus Extension");
707 
708  httpStatus = new HttpStatus( &gTVList, sched, gExpirer, ismaster );
709  pHS->RegisterExtension( httpStatus );
710  }
711 
712  be_sd_notify("STATUS=Creating main server");
713  mainServer = new MainServer(
714  ismaster, port, &gTVList, sched, gExpirer);
715 
716  int exitCode = mainServer->GetExitCode();
717  if (exitCode != GENERIC_EXIT_OK)
718  {
719  LOG(VB_GENERAL, LOG_CRIT,
720  "Backend exiting, MainServer initialization error.");
721  cleanup();
722  return exitCode;
723  }
724 
725  if (httpStatus && mainServer)
726  httpStatus->SetMainServer(mainServer);
727 
728  be_sd_notify("STATUS=Check all storage groups");
730 
731  be_sd_notify("STATUS=Sending \"master started\" message");
733  gCoreContext->SendSystemEvent("MASTER_STARTED");
734 
735  // Provide systemd ready notification (for Type=notify)
736  be_sd_notify("READY=1");
737 
738  const HTTPServices be_services = {
739  { VIDEO_SERVICE, &MythHTTPService::Create<V2Video> },
740  { MYTH_SERVICE, &MythHTTPService::Create<V2Myth> },
741  { DVR_SERVICE, &MythHTTPService::Create<V2Dvr> },
742  { CONTENT_SERVICE, &MythHTTPService::Create<V2Content> },
743  { GUIDE_SERVICE, &MythHTTPService::Create<V2Guide> },
744  { CHANNEL_SERVICE, &MythHTTPService::Create<V2Channel> },
745  { STATUS_SERVICE, &MythHTTPService::Create<V2Status> },
746  { CAPTURE_SERVICE, &MythHTTPService::Create<V2Capture> },
747  { MUSIC_SERVICE, &MythHTTPService::Create<V2Music> },
748  { CONFIG_SERVICE, &MythHTTPService::Create<V2Config> },
749  };
750 
751  MythHTTPInstance::Addservices(be_services);
752 
753  // Send all unknown requests into the web app. make bookmarks and direct access work.
754  auto spa_index = [](auto && PH1) { return MythHTTPRewrite::RewriteToSPA(std::forward<decltype(PH1)>(PH1), "apps/backend/index.html"); };
755  MythHTTPInstance::AddErrorPageHandler({ "=404", spa_index });
756 
757  // Serve components of the backend web app as if they were hosted at '/'
758  auto main_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/main.js"); };
759  auto styles_css = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/styles.css"); };
760  auto polyfills_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/polyfills.js"); };
761  auto runtime_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/runtime.js"); };
762 
763  // Default index page
764  auto root = [](auto && PH1) { return MythHTTPRoot::RedirectRoot(std::forward<decltype(PH1)>(PH1), "apps/backend/index.html"); };
765 
766  const HTTPHandlers be_handlers = {
767  { "/main.js", main_js },
768  { "/styles.css", styles_css },
769  { "/polyfills.js", polyfills_js },
770  { "/runtime.js", runtime_js },
771  { "/", root }
772  };
773 
774  MythHTTPScopedInstance webserver(be_handlers);
775 
778  exitCode = qApp->exec();
781 
783  {
784  gCoreContext->SendSystemEvent("MASTER_SHUTDOWN");
785  qApp->processEvents();
786  }
787 
788  LOG(VB_GENERAL, LOG_NOTICE, "MythBackend exiting");
789  be_sd_notify("STOPPING=1\nSTATUS=Exiting");
790 
791  return exitCode;
792 }
793 
794 // This is a copy of the code from above, to start backend in a restricted mode, only running the web server
795 // when the database is unusable, so thet the user can use the web app to fix the settings.
796 
798 {
799  LOG(VB_GENERAL, LOG_NOTICE, "***********************************************************************");
800  LOG(VB_GENERAL, LOG_NOTICE, "***** MythBackend starting in Web App only mode for initial setup *****");
801  LOG(VB_GENERAL, LOG_NOTICE, "***** Use http://<yourBackend>:6544 to perform setup *****");
802  LOG(VB_GENERAL, LOG_NOTICE, "***********************************************************************");
803 
804  const HTTPServices be_services = {
805  { VIDEO_SERVICE, &MythHTTPService::Create<V2Video> },
806  { MYTH_SERVICE, &MythHTTPService::Create<V2Myth> },
807  { DVR_SERVICE, &MythHTTPService::Create<V2Dvr> },
808  { CONTENT_SERVICE, &MythHTTPService::Create<V2Content> },
809  { GUIDE_SERVICE, &MythHTTPService::Create<V2Guide> },
810  { CHANNEL_SERVICE, &MythHTTPService::Create<V2Channel> },
811  { STATUS_SERVICE, &MythHTTPService::Create<V2Status> },
812  { CAPTURE_SERVICE, &MythHTTPService::Create<V2Capture> },
813  { MUSIC_SERVICE, &MythHTTPService::Create<V2Music> },
814  { CONFIG_SERVICE, &MythHTTPService::Create<V2Config> },
815  };
816 
817  MythHTTPInstance::Addservices(be_services);
818 
819  // Send all unknown requests into the web app. make bookmarks and direct access work.
820  auto spa_index = [](auto && PH1) { return MythHTTPRewrite::RewriteToSPA(std::forward<decltype(PH1)>(PH1), "apps/backend/index.html"); };
821  MythHTTPInstance::AddErrorPageHandler({ "=404", spa_index });
822 
823  // Serve components of the backend web app as if they were hosted at '/'
824  auto main_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/main.js"); };
825  auto styles_css = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/styles.css"); };
826  auto polyfills_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/polyfills.js"); };
827  auto runtime_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/runtime.js"); };
828 
829  // Default index page
830  auto root = [](auto && PH1) { return MythHTTPRoot::RedirectRoot(std::forward<decltype(PH1)>(PH1), "apps/backend/index.html"); };
831 
832  const HTTPHandlers be_handlers = {
833  { "/main.js", main_js },
834  { "/styles.css", styles_css },
835  { "/polyfills.js", polyfills_js },
836  { "/runtime.js", runtime_js },
837  { "/", root }
838  };
839 
840  MythHTTPScopedInstance webserver(be_handlers);
841 
844  // Provide systemd ready notification (for Type=notify)
845  be_sd_notify("READY=1\nSTATUS=Started in 'Web App only mode'");
846  int exitCode = qApp->exec();
847 
848  be_sd_notify("STOPPING=1\nSTATUS='Exiting Web App only mode'");
849  LOG(VB_GENERAL, LOG_NOTICE, "MythBackend Web App only mode exiting");
850  return exitCode;
851 }
setupTVs
bool setupTVs(bool ismaster, bool &error)
Definition: mythbackend_main_helpers.cpp:87
run_setup_webserver
int run_setup_webserver()
Definition: mythbackend_main_helpers.cpp:797
Scheduler
Definition: scheduler.h:45
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
hardwareprofile.h
v2video.h
HouseKeeper
Manages registered HouseKeeperTasks and queues tasks for operation.
Definition: housekeeper.h:149
MythCoreContext::SendMessage
void SendMessage(const QString &message)
Definition: mythcorecontext.cpp:1517
GENERIC_EXIT_SETUP_ERROR
@ GENERIC_EXIT_SETUP_ERROR
Incorrectly setup system.
Definition: exitcodes.h:22
AutoExpire::PrintExpireList
void PrintExpireList(const QString &expHost="ALL")
Prints a summary of the files that can be deleted.
Definition: autoexpire.cpp:795
MythHTTPScopedInstance
Definition: mythhttpinstance.h:35
ThemeUpdateTask
Definition: backendhousekeeper.h:34
v2music.h
Scheduler::GetError
int GetError(void) const
Definition: scheduler.h:119
dbutil.h
backendcontext.h
EITCache::ClearChannelLocks
static MTV_PUBLIC void ClearChannelLocks(void)
Removes old channel locks, use it only at master backend start.
Definition: eitcache.cpp:463
CONTENT_SERVICE
#define CONTENT_SERVICE
Definition: v2content.h:34
error
static void error(const char *str,...)
Definition: vbi.cpp:36
MediaServer
Definition: mediaserver.h:32
MythCoreContext::GetScheduler
MythScheduler * GetScheduler(void)
Definition: mythcorecontext.cpp:1905
connect_to_master
int connect_to_master(void)
Definition: mythbackend_main_helpers.cpp:412
CONFIG_SERVICE
#define CONFIG_SERVICE
Definition: v2config.h:11
mythdb.h
HttpStatus
Definition: httpstatus.h:42
cmdline
MythCommFlagCommandLineParser cmdline
Definition: mythcommflag.cpp:72
TVRec::Init
bool Init(void)
Performs instance initialization, returns true on success.
Definition: tv_rec.cpp:157
gPidFile
static QString gPidFile
Definition: mythbackend_main_helpers.cpp:85
BackendContext
Definition: backendcontext.h:33
MythCoreContext::ConnectToMasterServer
bool ConnectToMasterServer(bool blockingClient=true, bool openEventSocket=true)
Definition: mythcorecontext.cpp:357
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
logLevel
LogLevel_t logLevel
Definition: logging.cpp:85
TaskQueue::RequestTerminate
void RequestTerminate()
Definition: taskqueue.cpp:102
gExpirer
AutoExpire * gExpirer
Definition: backendcontext.cpp:8
gHousekeeping
static HouseKeeper * gHousekeeping
Definition: mythbackend_main_helpers.cpp:80
HttpServer::RegisterExtension
void RegisterExtension(HttpServerExtension *pExtension)
Definition: httpserver.cpp:321
MythCoreContext::SetScheduler
void SetScheduler(MythScheduler *sched)
Definition: mythcorecontext.cpp:1900
Scheduler::FillRecordListFromDB
void FillRecordListFromDB(uint recordid=0)
Definition: scheduler.cpp:491
v2content.h
httpstatus.h
MythContext::setWebOnly
void setWebOnly(WebOnlyStartup w)
Definition: mythcontext.h:68
sched
Scheduler * sched
mythhttpinstance.h
RadioStreamUpdateTask
Definition: backendhousekeeper.h:22
MythCoreContext::IsDatabaseIgnored
bool IsDatabaseIgnored(void) const
/brief Returns true if database is being ignored.
Definition: mythcorecontext.cpp:876
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
MainServer
Definition: mainserver.h:115
AutoExpire
Used to expire recordings to make space for new recordings.
Definition: autoexpire.h:60
v2myth.h
Scheduler::DisableScheduling
void DisableScheduling(void)
Definition: scheduler.h:109
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:619
UPnp::GetHttpServer
HttpServer * GetHttpServer()
Definition: upnp.h:128
MythCoreContext::CheckProtoVersion
bool CheckProtoVersion(MythSocket *socket, std::chrono::milliseconds timeout=kMythSocketLongTimeout, bool error_dialog_desired=false)
Definition: mythcorecontext.cpp:1661
MythContext::kWebOnlyIPAddress
@ kWebOnlyIPAddress
Definition: mythcontext.h:64
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
mythsystemevent.h
build_compdb.file
file
Definition: build_compdb.py:55
GENERIC_EXIT_INVALID_TIME
@ GENERIC_EXIT_INVALID_TIME
Invalid time.
Definition: exitcodes.h:23
HouseKeeper::RegisterTask
void RegisterTask(HouseKeeperTask *task)
Definition: housekeeper.cpp:642
gBackendContext
BackendContext * gBackendContext
Definition: backendcontext.cpp:9
HttpStatus::SetMainServer
void SetMainServer(MainServer *mainServer)
Definition: httpstatus.h:88
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:11
v2dvr.h
remoteutil.h
scheduler.h
be_sd_notify
static void be_sd_notify(const char *)
Definition: mythbackend_main_helpers.cpp:6
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
VIDEO_SERVICE
#define VIDEO_SERVICE
Definition: v2video.h:13
MythSocket
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:25
MythContext::kWebOnlyDBTimezone
@ kWebOnlyDBTimezone
Definition: mythcontext.h:62
mythbackend_commandlineparser.h
SSDP::Instance
static SSDP * Instance()
Definition: ssdp.cpp:55
MythCoreContext::IsMasterBackend
bool IsMasterBackend(void)
is this the actual MBE process
Definition: mythcorecontext.cpp:695
MythHTTPRewrite::RewriteFile
static HTTPResponse RewriteFile(const HTTPRequest2 &Request, const QString &File)
A convenience method to seemlessly redirect requests for files to a context specific file.
Definition: mythhttprewrite.cpp:22
v2channel.h
autoexpire.h
MythHTTPInstance::Addservices
static void Addservices(const HTTPServices &Services)
Definition: mythhttpinstance.cpp:102
programinfo.h
mythlogging.h
UpgradeTVDatabaseSchema
bool UpgradeTVDatabaseSchema(const bool upgradeAllowed, const bool upgradeIfNoUI, [[maybe_unused]] const bool informSystemd)
Called from outside dbcheck.cpp to update the schema.
Definition: dbcheck.cpp:361
dbcheck.h
MythCoreContext::GetBackendServerPort
int GetBackendServerPort(void)
Returns the locally defined backend control port.
Definition: mythcorecontext.cpp:1064
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1544
MythCoreContext::GetMasterServerIP
QString GetMasterServerIP(void)
Returns the Master Backend IP address If the address is an IPv6 address, the scope Id is removed.
Definition: mythcorecontext.cpp:966
signalhandling.h
verboseMask
uint64_t verboseMask
Definition: logging.cpp:97
MSqlQuery::first
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
Definition: mythdbcon.cpp:823
TaskQueue::Instance
static TaskQueue * Instance()
Definition: taskqueue.cpp:59
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:551
compat.h
MythCoreContext::GetBackendServerIP
QString GetBackendServerIP(void)
Returns the IP address of the locally defined backend IP.
Definition: mythcorecontext.cpp:1004
MythCoreContext::SetDVBv3
void SetDVBv3(bool dvbv3)
Definition: mythcorecontext.h:329
eitcache.h
GENERIC_EXIT_SOCKET_ERROR
@ GENERIC_EXIT_SOCKET_ERROR
Socket error.
Definition: exitcodes.h:19
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
mythhttprewrite.h
Scheduler::SetExpirer
void SetExpirer(AutoExpire *autoExpirer)
Definition: scheduler.h:55
MythCoreContext::GetDB
MythDB * GetDB(void)
Definition: mythcorecontext.cpp:1753
mythtranslation.h
v2capture.h
MythTZ
Definition: mythtimezone.cpp:17
HardwareProfileTask
Definition: hardwareprofile.h:52
scheduledrecording.h
ArtworkTask
Definition: backendhousekeeper.h:49
DBUtil::CheckTimeZoneSupport
static bool CheckTimeZoneSupport(void)
Check if MySQL has working timz zone support.
Definition: dbutil.cpp:863
CHANNEL_SERVICE
#define CHANNEL_SERVICE
Definition: v2channel.h:39
storagegroup.h
jobqueue.h
Scheduler::PrintList
void PrintList(bool onlyFutureRecordings=false)
Definition: scheduler.h:98
TVRec::s_inputsLock
static QReadWriteLock s_inputsLock
Definition: tv_rec.h:432
g_pUPnp
static MediaServer * g_pUPnp
Definition: mythbackend_main_helpers.cpp:83
DVR_SERVICE
#define DVR_SERVICE
Definition: v2dvr.h:39
MythContext::kWebOnlySchemaUpdate
@ kWebOnlySchemaUpdate
Definition: mythcontext.h:65
uint
unsigned int uint
Definition: compat.h:81
MythHTTPRoot::RedirectRoot
static HTTPResponse RedirectRoot(const HTTPRequest2 &Request, const QString &File)
A convenience method to seemlessly redirect requests for index.html to a context specific file.
Definition: mythhttproot.cpp:24
gTVList
QMap< int, EncoderLink * > gTVList
Definition: backendcontext.cpp:7
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
JobQueueRecoverTask
Definition: backendhousekeeper.h:62
v2config.h
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:912
MediaServer::Init
void Init(bool bIsMaster, bool bDisableUPnp=false)
Definition: mediaserver.cpp:64
mainServer
static MainServer * mainServer
Definition: mythbackend_main_helpers.cpp:84
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:34
MainServer::GetExitCode
int GetExitCode() const
Definition: mainserver.h:152
STATUS_SERVICE
#define STATUS_SERVICE
Definition: v2status.h:34
GUIDE_SERVICE
#define GUIDE_SERVICE
Definition: v2guide.h:43
MythCoreContext::GetMasterServerPort
static int GetMasterServerPort(void)
Returns the Master Backend control port If no master server port has been defined in the database,...
Definition: mythcorecontext.cpp:980
backendhousekeeper.h
mediaserver.h
GENERIC_EXIT_CONNECT_ERROR
@ GENERIC_EXIT_CONNECT_ERROR
Can't connect to master backend.
Definition: exitcodes.h:21
CleanupTask
Definition: backendhousekeeper.h:7
MythCommandLineParser::toString
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2344
mythhttproot.h
MythCommandLineParser::toBool
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
Definition: mythcommandlineparser.cpp:2187
gSysEventHandler
static MythSystemEventHandler * gSysEventHandler
Definition: mythbackend_main_helpers.cpp:82
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
CAPTURE_SERVICE
#define CAPTURE_SERVICE
Definition: v2capture.h:33
TVRec
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:142
mythcontext.h
tv_rec.h
v2guide.h
handle_command
int handle_command(const MythBackendCommandLineParser &cmdline)
Definition: mythbackend_main_helpers.cpp:331
MYTH_SERVICE
#define MYTH_SERVICE
Definition: v2myth.h:16
ChannelGroup::UpdateChannelGroups
static void UpdateChannelGroups(void)
Definition: channelgroup.cpp:468
HttpServer
Definition: httpserver.h:112
mainserver.h
MUSIC_SERVICE
#define MUSIC_SERVICE
Definition: v2music.h:17
JobQueue
Definition: jobqueue.h:128
mythbackend_main_helpers.h
MythContext::kWebOnlyWebOnlyParm
@ kWebOnlyWebOnlyParm
Definition: mythcontext.h:63
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:838
MythBackendCommandLineParser
Definition: mythbackend_commandlineparser.h:7
HTTPServices
std::vector< HTTPService > HTTPServices
Definition: mythhttptypes.h:54
gJobQueue
static JobQueue * gJobQueue
Definition: mythbackend_main_helpers.cpp:81
MythCoreContext::IsMasterHost
bool IsMasterHost(void)
is this the same host as the master
Definition: mythcorecontext.cpp:659
musicbrainzngs.caa.hostname
string hostname
Definition: caa.py:17
previewgenerator.h
MythFillDatabaseTask
Definition: backendhousekeeper.h:71
ProgramInfo::CheckProgramIDAuthorities
static void CheckProgramIDAuthorities(void)
Definition: programinfo.cpp:2361
MythTranslation::load
static void load(const QString &module_name)
Load a QTranslator for the user's preferred language.
Definition: mythtranslation.cpp:37
exitcodes.h
MainServer::Stop
void Stop(void)
Definition: mainserver.cpp:366
run_backend
int run_backend(MythBackendCommandLineParser &cmdline)
Definition: mythbackend_main_helpers.cpp:524
MythSystemEventHandler
Handles incoming MythSystemEvent messages.
Definition: mythsystemevent.h:24
Scheduler::FillRecordListFromMaster
void FillRecordListFromMaster(void)
Definition: scheduler.cpp:574
cleanup
void cleanup(void)
Definition: mythbackend_main_helpers.cpp:262
print_warnings
void print_warnings(const MythBackendCommandLineParser &cmdline)
Definition: mythbackend_main_helpers.cpp:496
StorageGroup::CheckAllStorageGroupDirs
static void CheckAllStorageGroupDirs(void)
Definition: storagegroup.cpp:724
gContext
MythContext * gContext
This global variable contains the MythContext instance for the application.
Definition: mythcontext.cpp:64
HouseKeeper::Start
void Start(void)
Definition: housekeeper.cpp:676
MythHTTPRewrite::RewriteToSPA
static HTTPResponse RewriteToSPA(const HTTPRequest2 &Request, const QString &File)
A convenience method to seemlessly redirect requests to a Single Page web app (SPA)
Definition: mythhttprewrite.cpp:50
mythtimezone.h
SignalHandler::Done
static void Done(void)
Definition: signalhandling.cpp:134
MythCoreContext::SetExiting
void SetExiting(bool exiting=true)
Definition: mythcorecontext.cpp:2112
TVRec::GetTVRec
static TVRec * GetTVRec(uint inputid)
Definition: tv_rec.cpp:4878
v2status.h
SSDP::RequestTerminate
void RequestTerminate(void)
Definition: ssdp.cpp:139
HTTPHandlers
std::vector< HTTPHandler > HTTPHandlers
Definition: mythhttptypes.h:47
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:838
TVRec::s_inputs
static QMap< uint, TVRec * > s_inputs
Definition: tv_rec.h:433
MythHTTPInstance::AddErrorPageHandler
static void AddErrorPageHandler(const HTTPHandler &Handler)
Definition: mythhttpinstance.cpp:112
LOC
#define LOC
Definition: mythbackend_main_helpers.cpp:76