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"
40#include "libmythtv/dbcheck.h"
41#include "libmythtv/eitcache.h"
42#include "libmythtv/jobqueue.h"
46#include "libmythtv/tv_rec.h"
47#include "libmythupnp/ssdp.h"
49
50// MythBackend
51#include "autoexpire.h"
52#include "backendcontext.h"
53#include "backendhousekeeper.h"
54#include "encoderlink.h"
55#include "httpstatus.h"
56#include "mainserver.h"
57#include "mediaserver.h"
60#include "scheduler.h"
61
62// New webserver
66#include "servicesv2/v2myth.h"
67#include "servicesv2/v2video.h"
68#include "servicesv2/v2dvr.h"
70#include "servicesv2/v2guide.h"
72#include "servicesv2/v2status.h"
74#include "servicesv2/v2music.h"
75#include "servicesv2/v2config.h"
76
77#define LOC QString("MythBackend: ")
78#define LOC_WARN QString("MythBackend, Warning: ")
79#define LOC_ERR QString("MythBackend, Error: ")
80
81static HouseKeeper *gHousekeeping { nullptr };
82static JobQueue *gJobQueue { nullptr };
84static MediaServer *g_pUPnp { nullptr };
85static MainServer *mainServer { nullptr };
86
87bool 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 {
122 MythDB::DBError("Querying minimum chanid", query);
123 }
124
125 MSqlQuery records_without_station(MSqlQuery::InitCon());
126 records_without_station.prepare("SELECT record.chanid,"
127 " channel.callsign FROM record LEFT JOIN channel"
128 " ON record.chanid = channel.chanid WHERE record.station='';");
129 if (records_without_station.exec())
130 {
131 MSqlQuery update_record(MSqlQuery::InitCon());
132 update_record.prepare("UPDATE record SET station = :CALLSIGN"
133 " WHERE chanid = :CHANID;");
134 while (records_without_station.next())
135 {
136 update_record.bindValue(":CALLSIGN",
137 records_without_station.value(1));
138 update_record.bindValue(":CHANID",
139 records_without_station.value(0));
140 if (!update_record.exec())
141 {
142 MythDB::DBError("Updating record station", update_record);
143 }
144 }
145 }
146 }
147
148 if (!query.exec(
149 "SELECT cardid, parentid, videodevice, hostname, sourceid "
150 "FROM capturecard "
151 "ORDER BY cardid"))
152 {
153 MythDB::DBError("Querying Recorders", query);
154 return false;
155 }
156
157 std::vector<unsigned int> cardids;
158 std::vector<QString> hosts;
159 while (query.next())
160 {
161 uint cardid = query.value(0).toUInt();
162 uint parentid = query.value(1).toUInt();
163 QString videodevice = query.value(2).toString();
164 QString hostname = query.value(3).toString();
165 uint sourceid = query.value(4).toUInt();
166 QString cidmsg = QString("Card[%1](%2)").arg(cardid).arg(videodevice);
167
168 if (hostname.isEmpty())
169 {
170 LOG(VB_GENERAL, LOG_ERR, cidmsg +
171 " does not have a hostname defined.\n"
172 "Please run setup and confirm all of the capture cards.\n");
173 continue;
174 }
175
176 // Skip all cards that do not have a video source
177 if (sourceid == 0)
178 {
179 if (parentid == 0)
180 {
181 LOG(VB_GENERAL, LOG_WARNING, cidmsg +
182 " does not have a video source");
183 }
184 continue;
185 }
186
187 cardids.push_back(cardid);
188 hosts.push_back(hostname);
189 }
190
191 QWriteLocker tvlocker(&TVRec::s_inputsLock);
192
193 // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
194 for (size_t i = 0; i < cardids.size(); i++)
195 {
196 if (hosts[i] == localhostname) {
197 // No memory leak. The constructor for TVRec adds the item
198 // to the static map TVRec::s_inputs.
199 new TVRec(cardids[i]);
200 }
201 }
202
203 for (size_t i = 0; i < cardids.size(); i++)
204 {
205 uint cardid = cardids[i];
206 const QString& host = hosts[i];
207 QString cidmsg = QString("Card %1").arg(cardid);
208
209 if (!ismaster)
210 {
211 if (host == localhostname)
212 {
213 TVRec *tv = TVRec::GetTVRec(cardid);
214 if (tv && tv->Init())
215 {
216 auto *enc = new EncoderLink(cardid, tv);
217 gTVList[cardid] = enc;
218 }
219 else
220 {
221 LOG(VB_GENERAL, LOG_ERR, "Problem with capture cards. " +
222 cidmsg + " failed init");
223 delete tv;
224 // No longer set an error here, because we need the
225 // slave backend to be able to start without a capture
226 // card, so that it can be setup through the web app
227 }
228 }
229 }
230 else
231 {
232 if (host == localhostname)
233 {
234 TVRec *tv = TVRec::GetTVRec(cardid);
235 if (tv && tv->Init())
236 {
237 auto *enc = new EncoderLink(cardid, tv);
238 gTVList[cardid] = enc;
239 }
240 else
241 {
242 LOG(VB_GENERAL, LOG_ERR, "Problem with capture cards. " +
243 cidmsg + " failed init");
244 delete tv;
245 }
246 }
247 else
248 {
249 auto *enc = new EncoderLink(cardid, nullptr, host);
250 gTVList[cardid] = enc;
251 }
252 }
253 }
254
255 if (gTVList.empty())
256 {
257 LOG(VB_GENERAL, LOG_WARNING, LOC +
258 "No valid capture cards are defined in the database.");
259 }
260
261 return true;
262}
263
264void cleanup(void)
265{
266 if (mainServer)
267 {
268 mainServer->Stop();
269 qApp->processEvents();
270 }
271
272 if (gCoreContext)
274
275 delete gSysEventHandler;
276 gSysEventHandler = nullptr;
277
278 delete gHousekeeping;
279 gHousekeeping = nullptr;
280
281 if (gCoreContext)
282 {
283 delete gCoreContext->GetScheduler();
284 gCoreContext->SetScheduler(nullptr);
285 }
286
287 delete gExpirer;
288 gExpirer = nullptr;
289
290 delete gJobQueue;
291 gJobQueue = nullptr;
292
293 delete g_pUPnp;
294 g_pUPnp = nullptr;
295
296 if (SSDP::Instance())
297 {
299 SSDP::Instance()->wait();
300 }
301
303 {
306 }
307
308 while (!TVRec::s_inputs.empty())
309 {
310 TVRec *rec = *TVRec::s_inputs.begin();
311 delete rec;
312 }
313
314 delete mainServer;
315 mainServer = nullptr;
316
317 delete gBackendContext;
318 gBackendContext = nullptr;
319}
320
322{
323 if (cmdline.toBool("setverbose"))
324 {
326 {
327 QString message = "SET_VERBOSE ";
328 message += cmdline.toString("setverbose");
329
330 gCoreContext->SendMessage(message);
331 LOG(VB_GENERAL, LOG_INFO,
332 QString("Sent '%1' message").arg(message));
333 return GENERIC_EXIT_OK;
334 }
335 LOG(VB_GENERAL, LOG_ERR,
336 "Unable to connect to backend, verbose mask unchanged ");
338 }
339
340 if (cmdline.toBool("setloglevel"))
341 {
343 {
344 QString message = "SET_LOG_LEVEL ";
345 message += cmdline.toString("setloglevel");
346
347 gCoreContext->SendMessage(message);
348 LOG(VB_GENERAL, LOG_INFO,
349 QString("Sent '%1' message").arg(message));
350 return GENERIC_EXIT_OK;
351 }
352 LOG(VB_GENERAL, LOG_ERR,
353 "Unable to connect to backend, log level unchanged ");
355 }
356
357 if (cmdline.toBool("printsched") ||
358 cmdline.toBool("testsched"))
359 {
360 auto *sched = new Scheduler(false, &gTVList);
361 if (cmdline.toBool("printsched"))
362 {
364 {
365 LOG(VB_GENERAL, LOG_ERR, "Cannot connect to master");
366 delete sched;
368 }
369 std::cout << "Retrieving Schedule from Master backend.\n";
371 }
372 else
373 {
374 std::cout << "Calculating Schedule from database.\n" <<
375 "Inputs, Card IDs, and Conflict info may be invalid "
376 "if you have multiple tuners.\n";
379 }
380
381 verboseMask |= VB_SCHEDULE;
382 LogLevel_t oldLogLevel = logLevel;
383 logLevel = LOG_DEBUG;
384 sched->PrintList(true);
385 logLevel = oldLogLevel;
386 delete sched;
387 return GENERIC_EXIT_OK;
388 }
389
390 if (cmdline.toBool("printexpire"))
391 {
392 gExpirer = new AutoExpire();
393 gExpirer->PrintExpireList(cmdline.toString("printexpire"));
394 return GENERIC_EXIT_OK;
395 }
396
397 // This should never actually be reached..
398 return GENERIC_EXIT_OK;
399}
400using namespace MythTZ;
401
403{
404 auto *tempMonitorConnection = new MythSocket();
405 if (tempMonitorConnection->ConnectToHost(
408 {
409 if (!gCoreContext->CheckProtoVersion(tempMonitorConnection))
410 {
411 LOG(VB_GENERAL, LOG_ERR, "Master backend is incompatible with "
412 "this backend.\nCannot become a slave.");
413 tempMonitorConnection->DecrRef();
415 }
416
417 QStringList tempMonitorDone("DONE");
418
419 QStringList tempMonitorAnnounce(QString("ANN Monitor %1 0")
420 .arg(gCoreContext->GetHostName()));
421 tempMonitorConnection->SendReceiveStringList(tempMonitorAnnounce);
422 if (tempMonitorAnnounce.empty() ||
423 tempMonitorAnnounce[0] == "ERROR")
424 {
425 tempMonitorConnection->DecrRef();
426 tempMonitorConnection = nullptr;
427 if (tempMonitorAnnounce.empty())
428 {
429 LOG(VB_GENERAL, LOG_ERR, LOC +
430 "Failed to open event socket, timeout");
431 }
432 else
433 {
434 LOG(VB_GENERAL, LOG_ERR, LOC +
435 "Failed to open event socket" +
436 ((tempMonitorAnnounce.size() >= 2) ?
437 QString(", error was %1").arg(tempMonitorAnnounce[1]) :
438 QString(", remote error")));
439 }
440 }
441
442 QStringList timeCheck;
443 if (tempMonitorConnection)
444 {
445 timeCheck.push_back("QUERY_TIME_ZONE");
446 tempMonitorConnection->SendReceiveStringList(timeCheck);
447 tempMonitorConnection->WriteStringList(tempMonitorDone);
448 }
449 if (timeCheck.size() < 3)
450 {
451 if (tempMonitorConnection)
452 tempMonitorConnection->DecrRef();
454 }
455
456 QDateTime our_time = MythDate::current();
457 QDateTime master_time = MythDate::fromString(timeCheck[2]);
458 int timediff = abs(our_time.secsTo(master_time));
459
460 if (timediff > 300)
461 {
462 LOG(VB_GENERAL, LOG_ERR,
463 QString("Current time on the master backend differs by "
464 "%1 seconds from time on this system. Exiting.")
465 .arg(timediff));
466 if (tempMonitorConnection)
467 tempMonitorConnection->DecrRef();
469 }
470
471 if (timediff > 20)
472 {
473 LOG(VB_GENERAL, LOG_WARNING,
474 QString("Time difference between the master "
475 "backend and this system is %1 seconds.")
476 .arg(timediff));
477 }
478 }
479 if (tempMonitorConnection)
480 tempMonitorConnection->DecrRef();
481
482 return GENERIC_EXIT_OK;
483}
484
485
487{
488 if (cmdline.toBool("nohousekeeper"))
489 {
490 LOG(VB_GENERAL, LOG_WARNING, LOC +
491 "****** The Housekeeper has been DISABLED with "
492 "the --nohousekeeper option ******");
493 }
494 if (cmdline.toBool("nosched"))
495 {
496 LOG(VB_GENERAL, LOG_WARNING, LOC +
497 "********** The Scheduler has been DISABLED with "
498 "the --nosched option **********");
499 }
500 if (cmdline.toBool("noautoexpire"))
501 {
502 LOG(VB_GENERAL, LOG_WARNING, LOC +
503 "********* Auto-Expire has been DISABLED with "
504 "the --noautoexpire option ********");
505 }
506 if (cmdline.toBool("nojobqueue"))
507 {
508 LOG(VB_GENERAL, LOG_WARNING, LOC +
509 "********* The JobQueue has been DISABLED with "
510 "the --nojobqueue option *********");
511 }
512}
513
515{
517
519 {
520 return run_setup_webserver();
521 }
523 {
524 LOG(VB_GENERAL, LOG_ERR,
525 "MySQL time zone support is missing. "
526 "Please install it and try again. "
527 "See 'mysql_tzinfo_to_sql' for assistance.");
528 gCoreContext->GetDB()->IgnoreDatabase(true);
530 return run_setup_webserver();
531 }
532 bool ismaster = gCoreContext->IsMasterHost();
533
534 if (!UpgradeTVDatabaseSchema(ismaster, ismaster, true))
535 {
536 LOG(VB_GENERAL, LOG_ERR,
537 QString("Couldn't upgrade database to new schema on %1 backend.")
538 .arg(ismaster ? "master" : "slave"));
540 return run_setup_webserver();
541 }
542#ifndef NDEBUG
543 if (cmdline.toBool("upgradedbonly"))
544 {
545 LOG(VB_GENERAL, LOG_ERR, "Exiting as requested.");
546 return GENERIC_EXIT_OK;
547 }
548#endif
549
550 be_sd_notify("STATUS=Loading translation");
551 MythTranslation::load("mythfrontend");
552
553 if (cmdline.toBool("webonly"))
554 {
556 return run_setup_webserver();
557 }
558 if (!ismaster)
559 {
560 be_sd_notify("STATUS=Connecting to master backend");
561 int ret = connect_to_master();
562 if (ret != GENERIC_EXIT_OK)
563 return ret;
564 }
565
566 be_sd_notify("STATUS=Get backend server port");
568 if (gCoreContext->GetBackendServerIP().isEmpty())
569 {
570 std::cerr << "No setting found for this machine's BackendServerAddr.\n"
571 << "MythBackend starting in Web App only mode for initial setup.\n"
572 << "Use http://<yourBackend>:6544 to perform setup.\n";
574 return run_setup_webserver();
575 }
576
578
579 if (ismaster)
580 {
581 LOG(VB_GENERAL, LOG_NOTICE, LOC + "Starting up as the master server.");
582 }
583 else
584 {
585 LOG(VB_GENERAL, LOG_NOTICE, LOC + "Running as a slave backend.");
586 }
587
588 if (ismaster)
589 {
591 }
592
594
595 bool fatal_error = false;
596 bool runsched = setupTVs(ismaster, fatal_error);
597 if (fatal_error)
599
600 Scheduler *sched = nullptr;
601 if (ismaster)
602 {
603 if (runsched)
604 {
605 be_sd_notify("STATUS=Creating scheduler");
606 sched = new Scheduler(true, &gTVList);
607 int err = sched->GetError();
608 if (err)
609 {
610 delete sched;
611 return err;
612 }
613
614 if (cmdline.toBool("nosched"))
616 }
617
618 if (!cmdline.toBool("noautoexpire"))
619 {
621 if (sched)
623 }
626 }
627
628 if (!cmdline.toBool("nohousekeeper"))
629 {
630 be_sd_notify("STATUS=Creating housekeeper");
632
633 if (ismaster)
634 {
639
640 // only run this task if MythMusic is installed and we have a new enough schema
641 if (gCoreContext->GetNumSetting("MusicDBSchemaVer", 0) >= 1024)
643 }
644
646#ifdef __linux__
647 #ifdef CONFIG_BINDINGS_PYTHON
649 #endif
650#endif
651
653 }
654
655 if (!cmdline.toBool("nojobqueue"))
656 gJobQueue = new JobQueue(ismaster);
657
658 // ----------------------------------------------------------------------
659 //
660 // ----------------------------------------------------------------------
661
662 if (g_pUPnp == nullptr)
663 {
664 be_sd_notify("STATUS=Creating UPnP media server");
665 g_pUPnp = new MediaServer();
666
667 g_pUPnp->Init(ismaster, cmdline.toBool("noupnp"));
668 }
669
670 if (cmdline.toBool("dvbv3"))
671 {
672 LOG(VB_GENERAL, LOG_INFO, LOC + "Use legacy DVBv3 API");
673 gCoreContext->SetDVBv3(true);
674 }
675
676 // ----------------------------------------------------------------------
677 // Setup status server
678 // ----------------------------------------------------------------------
679
680 HttpStatus *httpStatus = nullptr;
682
683 if (pHS)
684 {
685 LOG(VB_GENERAL, LOG_INFO, "Main::Registering HttpStatus Extension");
686 be_sd_notify("STATUS=Registering HttpStatus Extension");
687
688 httpStatus = new HttpStatus( &gTVList, sched, ismaster );
689 pHS->RegisterExtension( httpStatus );
690 }
691
692 be_sd_notify("STATUS=Creating main server");
694 ismaster, port, &gTVList, sched, gExpirer);
695
696 int exitCode = mainServer->GetExitCode();
697 if (exitCode != GENERIC_EXIT_OK)
698 {
699 LOG(VB_GENERAL, LOG_CRIT,
700 "Backend exiting, MainServer initialization error.");
701 cleanup();
702 return exitCode;
703 }
704
705 if (httpStatus && mainServer)
706 httpStatus->SetMainServer(mainServer);
707
708 be_sd_notify("STATUS=Check all storage groups");
710
711 be_sd_notify("STATUS=Sending \"master started\" message");
713 gCoreContext->SendSystemEvent("MASTER_STARTED");
714
715 // Provide systemd ready notification (for Type=notify)
716 be_sd_notify("READY=1");
717
718 const HTTPServices be_services = {
719 { VIDEO_SERVICE, &MythHTTPService::Create<V2Video> },
720 { MYTH_SERVICE, &MythHTTPService::Create<V2Myth> },
721 { DVR_SERVICE, &MythHTTPService::Create<V2Dvr> },
722 { CONTENT_SERVICE, &MythHTTPService::Create<V2Content> },
723 { GUIDE_SERVICE, &MythHTTPService::Create<V2Guide> },
724 { CHANNEL_SERVICE, &MythHTTPService::Create<V2Channel> },
725 { STATUS_SERVICE, &MythHTTPService::Create<V2Status> },
726 { CAPTURE_SERVICE, &MythHTTPService::Create<V2Capture> },
727 { MUSIC_SERVICE, &MythHTTPService::Create<V2Music> },
728 { CONFIG_SERVICE, &MythHTTPService::Create<V2Config> },
729 };
730
732
733 // Send all unknown requests into the web app. make bookmarks and direct access work.
734 auto spa_index = [](auto && PH1) { return MythHTTPRewrite::RewriteToSPA(std::forward<decltype(PH1)>(PH1), "apps/backend/index.html"); };
735 MythHTTPInstance::AddErrorPageHandler({ "=404", spa_index });
736
737 // Serve components of the backend web app as if they were hosted at '/'
738 auto main_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/main.js"); };
739 auto styles_css = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/styles.css"); };
740 auto polyfills_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/polyfills.js"); };
741 auto runtime_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/runtime.js"); };
742
743 // Default index page
744 auto root = [](auto && PH1) { return MythHTTPRoot::RedirectRoot(std::forward<decltype(PH1)>(PH1), "apps/backend/index.html"); };
745
746 const HTTPHandlers be_handlers = {
747 { "/main.js", main_js },
748 { "/styles.css", styles_css },
749 { "/polyfills.js", polyfills_js },
750 { "/runtime.js", runtime_js },
751 { "/", root }
752 };
753
754 MythHTTPScopedInstance webserver(be_handlers);
755
758 exitCode = qApp->exec();
761
763 {
764 gCoreContext->SendSystemEvent("MASTER_SHUTDOWN");
765 qApp->processEvents();
766 }
767
768 LOG(VB_GENERAL, LOG_NOTICE, "MythBackend exiting");
769 be_sd_notify("STOPPING=1\nSTATUS=Exiting");
770
771 return exitCode;
772}
773
774// This is a copy of the code from above, to start backend in a restricted mode, only running the web server
775// when the database is unusable, so thet the user can use the web app to fix the settings.
776
778{
779 LOG(VB_GENERAL, LOG_NOTICE, "***********************************************************************");
780 LOG(VB_GENERAL, LOG_NOTICE, "***** MythBackend starting in Web App only mode for initial setup *****");
781 LOG(VB_GENERAL, LOG_NOTICE, "***** Use http://<yourBackend>:6544 to perform setup *****");
782 LOG(VB_GENERAL, LOG_NOTICE, "***********************************************************************");
783
784 const HTTPServices be_services = {
785 { VIDEO_SERVICE, &MythHTTPService::Create<V2Video> },
786 { MYTH_SERVICE, &MythHTTPService::Create<V2Myth> },
787 { DVR_SERVICE, &MythHTTPService::Create<V2Dvr> },
788 { CONTENT_SERVICE, &MythHTTPService::Create<V2Content> },
789 { GUIDE_SERVICE, &MythHTTPService::Create<V2Guide> },
790 { CHANNEL_SERVICE, &MythHTTPService::Create<V2Channel> },
791 { STATUS_SERVICE, &MythHTTPService::Create<V2Status> },
792 { CAPTURE_SERVICE, &MythHTTPService::Create<V2Capture> },
793 { MUSIC_SERVICE, &MythHTTPService::Create<V2Music> },
794 { CONFIG_SERVICE, &MythHTTPService::Create<V2Config> },
795 };
796
798
799 // Send all unknown requests into the web app. make bookmarks and direct access work.
800 auto spa_index = [](auto && PH1) { return MythHTTPRewrite::RewriteToSPA(std::forward<decltype(PH1)>(PH1), "apps/backend/index.html"); };
801 MythHTTPInstance::AddErrorPageHandler({ "=404", spa_index });
802
803 // Serve components of the backend web app as if they were hosted at '/'
804 auto main_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/main.js"); };
805 auto styles_css = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/styles.css"); };
806 auto polyfills_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/polyfills.js"); };
807 auto runtime_js = [](auto && PH1) { return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1), "apps/backend/runtime.js"); };
808
809 // Default index page
810 auto root = [](auto && PH1) { return MythHTTPRoot::RedirectRoot(std::forward<decltype(PH1)>(PH1), "apps/backend/index.html"); };
811
812 const HTTPHandlers be_handlers = {
813 { "/main.js", main_js },
814 { "/styles.css", styles_css },
815 { "/polyfills.js", polyfills_js },
816 { "/runtime.js", runtime_js },
817 { "/", root }
818 };
819
820 MythHTTPScopedInstance webserver(be_handlers);
821
824 // Provide systemd ready notification (for Type=notify)
825 be_sd_notify("READY=1\nSTATUS=Started in 'Web App only mode'");
826 int exitCode = qApp->exec();
827
828 be_sd_notify("STOPPING=1\nSTATUS='Exiting Web App only mode'");
829 LOG(VB_GENERAL, LOG_NOTICE, "MythBackend Web App only mode exiting");
830 return exitCode;
831}
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:803
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:152
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)
static SSDP * Instance()
Definition: ssdp.cpp:102
void RequestTerminate(void)
Definition: ssdp.cpp:186
void FillRecordListFromDB(uint recordid=0)
Definition: scheduler.cpp:492
void PrintList(bool onlyFutureRecordings=false)
Definition: scheduler.h:99
int GetError(void) const
Definition: scheduler.h:120
void DisableScheduling(void)
Definition: scheduler.h:110
void SetExpirer(AutoExpire *autoExpirer)
Definition: scheduler.h:55
void FillRecordListFromMaster(void)
Definition: scheduler.cpp:575
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:157
static TVRec * GetTVRec(uint inputid)
Definition: tv_rec.cpp:4905
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
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
unsigned int uint
Definition: freesurround.h:24
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
MythCommFlagCommandLineParser cmdline
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
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:43
#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