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