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); };
16 #include <sys/types.h>
20 #include <QCoreApplication>
36 #include "libmythbase/mythversion.h"
76 #define LOC QString("MythBackend: ")
77 #define LOC_WARN QString("MythBackend, Warning: ")
78 #define LOC_ERR QString("MythBackend, Error: ")
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 = '';"))
108 if (!query.
exec(
"UPDATE channel SET callsign=chanid "
109 "WHERE callsign IS NULL OR callsign='';"))
112 if (query.
exec(
"SELECT MIN(chanid) FROM channel;"))
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)))
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())
130 update_record.
prepare(
"UPDATE record SET station = :CALLSIGN"
131 " WHERE chanid = :CHANID;");
135 records_without_station.
value(1));
137 records_without_station.
value(0));
138 if (!update_record.
exec())
142 }
while (records_without_station.
next());
147 "SELECT cardid, parentid, videodevice, hostname, sourceid "
155 std::vector<unsigned int> cardids;
156 std::vector<QString> hosts;
161 QString videodevice = query.
value(2).toString();
164 QString cidmsg = QString(
"Card[%1](%2)").arg(cardid).arg(videodevice);
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");
179 LOG(VB_GENERAL, LOG_WARNING, cidmsg +
180 " does not have a video source");
185 cardids.push_back(cardid);
192 for (
size_t i = 0; i < cardids.size(); i++)
194 if (hosts[i] == localhostname) {
197 new TVRec(cardids[i]);
201 for (
size_t i = 0; i < cardids.size(); i++)
203 uint cardid = cardids[i];
204 QString host = hosts[i];
205 QString cidmsg = QString(
"Card %1").arg(cardid);
209 if (host == localhostname)
212 if (tv && tv->
Init())
219 LOG(VB_GENERAL, LOG_ERR,
"Problem with capture cards. " +
220 cidmsg +
" failed init");
230 if (host == localhostname)
233 if (tv && tv->
Init())
240 LOG(VB_GENERAL, LOG_ERR,
"Problem with capture cards. " +
241 cidmsg +
" failed init");
247 auto *enc =
new EncoderLink(cardid,
nullptr, host);
255 LOG(VB_GENERAL, LOG_WARNING,
LOC +
256 "No valid capture cards are defined in the database.");
267 qApp->processEvents();
337 QString message =
"SET_VERBOSE ";
341 LOG(VB_GENERAL, LOG_INFO,
342 QString(
"Sent '%1' message").arg(message));
345 LOG(VB_GENERAL, LOG_ERR,
346 "Unable to connect to backend, verbose mask unchanged ");
354 QString message =
"SET_LOG_LEVEL ";
358 LOG(VB_GENERAL, LOG_INFO,
359 QString(
"Sent '%1' message").arg(message));
362 LOG(VB_GENERAL, LOG_ERR,
363 "Unable to connect to backend, log level unchanged ");
375 LOG(VB_GENERAL, LOG_ERR,
"Cannot connect to master");
379 std::cout <<
"Retrieving Schedule from Master backend.\n";
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";
414 auto *tempMonitorConnection =
new MythSocket();
415 if (tempMonitorConnection->ConnectToHost(
421 LOG(VB_GENERAL, LOG_ERR,
"Master backend is incompatible with "
422 "this backend.\nCannot become a slave.");
423 tempMonitorConnection->DecrRef();
427 QStringList tempMonitorDone(
"DONE");
429 QStringList tempMonitorAnnounce(QString(
"ANN Monitor %1 0")
431 tempMonitorConnection->SendReceiveStringList(tempMonitorAnnounce);
432 if (tempMonitorAnnounce.empty() ||
433 tempMonitorAnnounce[0] ==
"ERROR")
435 tempMonitorConnection->DecrRef();
436 tempMonitorConnection =
nullptr;
437 if (tempMonitorAnnounce.empty())
439 LOG(VB_GENERAL, LOG_ERR,
LOC +
440 "Failed to open event socket, timeout");
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")));
452 QStringList timeCheck;
453 if (tempMonitorConnection)
455 timeCheck.push_back(
"QUERY_TIME_ZONE");
456 tempMonitorConnection->SendReceiveStringList(timeCheck);
457 tempMonitorConnection->WriteStringList(tempMonitorDone);
459 if (timeCheck.size() < 3)
461 if (tempMonitorConnection)
462 tempMonitorConnection->DecrRef();
468 int timediff = abs(our_time.secsTo(master_time));
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.")
476 if (tempMonitorConnection)
477 tempMonitorConnection->DecrRef();
483 LOG(VB_GENERAL, LOG_WARNING,
484 QString(
"Time difference between the master "
485 "backend and this system is %1 seconds.")
489 if (tempMonitorConnection)
490 tempMonitorConnection->DecrRef();
500 LOG(VB_GENERAL, LOG_WARNING,
LOC +
501 "****** The Housekeeper has been DISABLED with "
502 "the --nohousekeeper option ******");
506 LOG(VB_GENERAL, LOG_WARNING,
LOC +
507 "********** The Scheduler has been DISABLED with "
508 "the --nosched option **********");
512 LOG(VB_GENERAL, LOG_WARNING,
LOC +
513 "********* Auto-Expire has been DISABLED with "
514 "the --noautoexpire option ********");
518 LOG(VB_GENERAL, LOG_WARNING,
LOC +
519 "********* The JobQueue has been DISABLED with "
520 "the --nojobqueue option *********");
530 if (
file.open(QIODevice::WriteOnly))
532 qint64 pid = QCoreApplication::applicationPid();
533 file.write(qPrintable(QString(
"%1\n").arg(pid)));
538 LOG(VB_GENERAL, LOG_WARNING,
539 QString(
LOC +
"Cannot open pidfile named %1").arg(
gPidFile));
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.");
562 LOG(VB_GENERAL, LOG_ERR,
563 QString(
"Couldn't upgrade database to new schema on %1 backend.")
564 .arg(ismaster ?
"master" :
"slave"));
586 std::cerr <<
"No setting found for this machine's BackendServerAddr.\n"
587 <<
"Please run mythtv-setup on this machine.\n"
588 <<
"Go to page \"General\" / \"Host Address Backend Setup\" and examine the values.\n"
589 <<
"N.B. The default values are correct for a combined frontend/backend machine.\n"
590 <<
"Press Escape, select \"Save and Exit\" and exit mythtv-setup.\n"
591 <<
"Then start mythbackend again.\n";
599 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Starting up as the master server.");
603 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Running as a slave backend.");
613 bool fatal_error =
false;
614 bool runsched =
setupTVs(ismaster, fatal_error);
665 #ifdef CONFIG_BINDINGS_PYTHON
690 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Use legacy DVBv3 API");
703 LOG(VB_GENERAL, LOG_INFO,
"Main::Registering HttpStatus Extension");
704 be_sd_notify(
"STATUS=Registering HttpStatus Extension");
717 LOG(VB_GENERAL, LOG_CRIT,
718 "Backend exiting, MainServer initialization error.");
729 be_sd_notify(
"STATUS=Sending \"master started\" message");
757 auto styles_css = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/styles.css"); };
758 auto polyfills_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/polyfills.js"); };
759 auto runtime_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/runtime.js"); };
762 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<decltype(PH1)>(PH1),
"apps/backend/index.html"); };
765 {
"/main.js", main_js },
766 {
"/styles.css", styles_css },
767 {
"/polyfills.js", polyfills_js },
768 {
"/runtime.js", runtime_js },
776 exitCode = qApp->exec();
783 qApp->processEvents();
786 LOG(VB_GENERAL, LOG_NOTICE,
"MythBackend exiting");
797 LOG(VB_GENERAL, LOG_NOTICE,
"**********************************************************************");
798 LOG(VB_GENERAL, LOG_NOTICE,
"***** MythBackend starting in webapp only mode for initial setup *****");
799 LOG(VB_GENERAL, LOG_NOTICE,
"***** Use http://localhost:6744 to perform setup *****");
800 LOG(VB_GENERAL, LOG_NOTICE,
"**********************************************************************");
823 auto styles_css = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/styles.css"); };
824 auto polyfills_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/polyfills.js"); };
825 auto runtime_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/runtime.js"); };
828 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<decltype(PH1)>(PH1),
"apps/backend/index.html"); };
831 {
"/main.js", main_js },
832 {
"/styles.css", styles_css },
833 {
"/polyfills.js", polyfills_js },
834 {
"/runtime.js", runtime_js },
842 int exitCode = qApp->exec();
844 LOG(VB_GENERAL, LOG_NOTICE,
"MythBackend setup webapp exiting");
bool setupTVs(bool ismaster, bool &error)
int run_setup_webserver()
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Manages registered HouseKeeperTasks and queues tasks for operation.
void SendMessage(const QString &message)
@ GENERIC_EXIT_SETUP_ERROR
Incorrectly setup system.
void PrintExpireList(const QString &expHost="ALL")
Prints a summary of the files that can be deleted.
static MTV_PUBLIC void ClearChannelLocks(void)
Removes old channel locks, use it only at master backend start.
Provides an interface to both local and remote TVRec's for the mythbackend.
static void error(const char *str,...)
MythScheduler * GetScheduler(void)
int connect_to_master(void)
MythCommFlagCommandLineParser cmdline
bool Init(void)
Performs instance initialization, returns true on success.
bool ConnectToMasterServer(bool blockingClient=true, bool openEventSocket=true)
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
static HouseKeeper * gHousekeeping
void RegisterExtension(HttpServerExtension *pExtension)
void SetScheduler(MythScheduler *sched)
void FillRecordListFromDB(uint recordid=0)
bool IsDatabaseIgnored(void) const
/brief Returns true if database is being ignored.
QVariant value(int i) const
Used to expire recordings to make space for new recordings.
void DisableScheduling(void)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
HttpServer * GetHttpServer()
bool CheckProtoVersion(MythSocket *socket, std::chrono::milliseconds timeout=kMythSocketLongTimeout, bool error_dialog_desired=false)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
@ GENERIC_EXIT_INVALID_TIME
Invalid time.
void RegisterTask(HouseKeeperTask *task)
BackendContext * gBackendContext
void SetMainServer(MainServer *mainServer)
@ GENERIC_EXIT_OK
Exited with no error.
static void be_sd_notify(const char *)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Class for communcating between myth backends and frontends.
bool IsMasterBackend(void)
is this the actual MBE process
static HTTPResponse RewriteFile(const HTTPRequest2 &Request, const QString &File)
A convenience method to seemlessly redirect requests for files to a context specific file.
static void Addservices(const HTTPServices &Services)
bool UpgradeTVDatabaseSchema(const bool upgradeAllowed, const bool upgradeIfNoUI, [[maybe_unused]] const bool informSystemd)
Called from outside dbcheck.cpp to update the schema.
int GetBackendServerPort(void)
Returns the locally defined backend control port.
void SendSystemEvent(const QString &msg)
QString GetMasterServerIP(void)
Returns the Master Backend IP address If the address is an IPv6 address, the scope Id is removed.
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
static TaskQueue * Instance()
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
QString GetBackendServerIP(void)
Returns the IP address of the locally defined backend IP.
void SetDVBv3(bool dvbv3)
@ GENERIC_EXIT_SOCKET_ERROR
Socket error.
static void DBError(const QString &where, const MSqlQuery &query)
void SetExpirer(AutoExpire *autoExpirer)
static bool CheckTimeZoneSupport(void)
Check if MySQL has working timz zone support.
void PrintList(bool onlyFutureRecordings=false)
static QReadWriteLock s_inputsLock
static MediaServer * g_pUPnp
static HTTPResponse RedirectRoot(const HTTPRequest2 &Request, const QString &File)
A convenience method to seemlessly redirect requests for index.html to a context specific file.
QMap< int, EncoderLink * > gTVList
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
int GetNumSetting(const QString &key, int defaultval=0)
static MainServer * mainServer
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
static int GetMasterServerPort(void)
Returns the Master Backend control port If no master server port has been defined in the database,...
@ GENERIC_EXIT_CONNECT_ERROR
Can't connect to master backend.
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
static MythSystemEventHandler * gSysEventHandler
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
This is the coordinating class of the Recorder Subsystem.
int handle_command(const MythBackendCommandLineParser &cmdline)
static void UpdateChannelGroups(void)
QString GetHostName(void)
std::vector< HTTPService > HTTPServices
static JobQueue * gJobQueue
bool IsMasterHost(void)
is this the same host as the master
static void CheckProgramIDAuthorities(void)
static void load(const QString &module_name)
Load a QTranslator for the user's preferred language.
int run_backend(MythBackendCommandLineParser &cmdline)
Handles incoming MythSystemEvent messages.
void FillRecordListFromMaster(void)
void print_warnings(const MythBackendCommandLineParser &cmdline)
static void CheckAllStorageGroupDirs(void)
MythContext * gContext
This global variable contains the MythContext instance for the application.
static HTTPResponse RewriteToSPA(const HTTPRequest2 &Request, const QString &File)
A convenience method to seemlessly redirect requests to a Single Page web app (SPA)
void SetExiting(bool exiting=true)
static TVRec * GetTVRec(uint inputid)
void RequestTerminate(void)
std::vector< HTTPHandler > HTTPHandlers
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
static QMap< uint, TVRec * > s_inputs
static void AddErrorPageHandler(const HTTPHandler &Handler)