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: ")
94 if (!query.
exec(
"UPDATE recorded SET basename = CONCAT(chanid, '_', "
95 "DATE_FORMAT(starttime, '%Y%m%d%H%i00'), '_', "
96 "DATE_FORMAT(endtime, '%Y%m%d%H%i00'), '.nuv') "
97 "WHERE basename = '';"))
103 if (!query.
exec(
"UPDATE channel SET callsign=chanid "
104 "WHERE callsign IS NULL OR callsign='';"))
107 if (query.
exec(
"SELECT MIN(chanid) FROM channel;"))
110 int min_chanid = query.
value(0).toInt();
111 if (!query.
exec(QString(
"UPDATE record SET chanid = %1 "
112 "WHERE chanid IS NULL;").arg(min_chanid)))
119 records_without_station.
prepare(
"SELECT record.chanid,"
120 " channel.callsign FROM record LEFT JOIN channel"
121 " ON record.chanid = channel.chanid WHERE record.station='';");
122 if (records_without_station.
exec() && records_without_station.
next())
125 update_record.
prepare(
"UPDATE record SET station = :CALLSIGN"
126 " WHERE chanid = :CHANID;");
130 records_without_station.
value(1));
132 records_without_station.
value(0));
133 if (!update_record.
exec())
137 }
while (records_without_station.
next());
142 "SELECT cardid, parentid, videodevice, hostname, sourceid "
150 std::vector<unsigned int> cardids;
151 std::vector<QString> hosts;
156 QString videodevice = query.
value(2).toString();
159 QString cidmsg = QString(
"Card[%1](%2)").arg(cardid).arg(videodevice);
163 LOG(VB_GENERAL, LOG_ERR, cidmsg +
164 " does not have a hostname defined.\n"
165 "Please run setup and confirm all of the capture cards.\n");
174 LOG(VB_GENERAL, LOG_WARNING, cidmsg +
175 " does not have a video source");
180 cardids.push_back(cardid);
187 for (
size_t i = 0; i < cardids.size(); i++)
189 if (hosts[i] == localhostname) {
192 new TVRec(cardids[i]);
196 for (
size_t i = 0; i < cardids.size(); i++)
198 uint cardid = cardids[i];
199 QString host = hosts[i];
200 QString cidmsg = QString(
"Card %1").arg(cardid);
204 if (host == localhostname)
207 if (tv && tv->
Init())
214 LOG(VB_GENERAL, LOG_ERR,
"Problem with capture cards. " +
215 cidmsg +
" failed init");
225 if (host == localhostname)
228 if (tv && tv->
Init())
235 LOG(VB_GENERAL, LOG_ERR,
"Problem with capture cards. " +
236 cidmsg +
" failed init");
242 auto *enc =
new EncoderLink(cardid,
nullptr, host);
250 LOG(VB_GENERAL, LOG_WARNING,
LOC +
251 "No valid capture cards are defined in the database.");
262 qApp->processEvents();
319 unlink(
gPidFile.toLatin1().constData());
334 eventString =
"SYSTEM_EVENT " +
339 if (!eventString.isEmpty())
353 QString message =
"SET_VERBOSE ";
357 LOG(VB_GENERAL, LOG_INFO,
358 QString(
"Sent '%1' message").arg(message));
361 LOG(VB_GENERAL, LOG_ERR,
362 "Unable to connect to backend, verbose mask unchanged ");
370 QString message =
"SET_LOG_LEVEL ";
374 LOG(VB_GENERAL, LOG_INFO,
375 QString(
"Sent '%1' message").arg(message));
378 LOG(VB_GENERAL, LOG_ERR,
379 "Unable to connect to backend, log level unchanged ");
388 LOG(VB_GENERAL, LOG_INFO,
"Sent CLEAR_SETTINGS_CACHE message");
391 LOG(VB_GENERAL, LOG_ERR,
"Unable to connect to backend, settings "
392 "cache will not be cleared.");
404 LOG(VB_GENERAL, LOG_ERR,
"Cannot connect to master");
408 std::cout <<
"Retrieving Schedule from Master backend.\n";
413 std::cout <<
"Calculating Schedule from database.\n" <<
414 "Inputs, Card IDs, and Conflict info may be invalid "
415 "if you have multiple tuners.\n";
434 LOG(VB_GENERAL, LOG_INFO,
"Connected to master for reschedule");
436 "MythBackendCommand");
440 LOG(VB_GENERAL, LOG_ERR,
"Cannot connect to master for reschedule");
451 LOG(VB_GENERAL, LOG_INFO,
"Requested video scan");
455 LOG(VB_GENERAL, LOG_ERR,
"Cannot connect to master for video scan");
474 auto *tempMonitorConnection =
new MythSocket();
475 if (tempMonitorConnection->ConnectToHost(
481 LOG(VB_GENERAL, LOG_ERR,
"Master backend is incompatible with "
482 "this backend.\nCannot become a slave.");
483 tempMonitorConnection->DecrRef();
487 QStringList tempMonitorDone(
"DONE");
489 QStringList tempMonitorAnnounce(QString(
"ANN Monitor %1 0")
491 tempMonitorConnection->SendReceiveStringList(tempMonitorAnnounce);
492 if (tempMonitorAnnounce.empty() ||
493 tempMonitorAnnounce[0] ==
"ERROR")
495 tempMonitorConnection->DecrRef();
496 tempMonitorConnection =
nullptr;
497 if (tempMonitorAnnounce.empty())
499 LOG(VB_GENERAL, LOG_ERR,
LOC +
500 "Failed to open event socket, timeout");
504 LOG(VB_GENERAL, LOG_ERR,
LOC +
505 "Failed to open event socket" +
506 ((tempMonitorAnnounce.size() >= 2) ?
507 QString(
", error was %1").arg(tempMonitorAnnounce[1]) :
508 QString(
", remote error")));
512 QStringList timeCheck;
513 if (tempMonitorConnection)
515 timeCheck.push_back(
"QUERY_TIME_ZONE");
516 tempMonitorConnection->SendReceiveStringList(timeCheck);
517 tempMonitorConnection->WriteStringList(tempMonitorDone);
519 if (timeCheck.size() < 3)
521 if (tempMonitorConnection)
522 tempMonitorConnection->DecrRef();
528 int timediff = abs(our_time.secsTo(master_time));
532 LOG(VB_GENERAL, LOG_ERR,
533 QString(
"Current time on the master backend differs by "
534 "%1 seconds from time on this system. Exiting.")
536 if (tempMonitorConnection)
537 tempMonitorConnection->DecrRef();
543 LOG(VB_GENERAL, LOG_WARNING,
544 QString(
"Time difference between the master "
545 "backend and this system is %1 seconds.")
549 if (tempMonitorConnection)
550 tempMonitorConnection->DecrRef();
560 LOG(VB_GENERAL, LOG_WARNING,
LOC +
561 "****** The Housekeeper has been DISABLED with "
562 "the --nohousekeeper option ******");
566 LOG(VB_GENERAL, LOG_WARNING,
LOC +
567 "********** The Scheduler has been DISABLED with "
568 "the --nosched option **********");
572 LOG(VB_GENERAL, LOG_WARNING,
LOC +
573 "********* Auto-Expire has been DISABLED with "
574 "the --noautoexpire option ********");
578 LOG(VB_GENERAL, LOG_WARNING,
LOC +
579 "********* The JobQueue has been DISABLED with "
580 "the --nojobqueue option *********");
594 LOG(VB_GENERAL, LOG_ERR,
595 "MySQL time zone support is missing. "
596 "Please install it and try again. "
597 "See 'mysql_tzinfo_to_sql' for assistance.");
605 LOG(VB_GENERAL, LOG_ERR,
606 QString(
"Couldn't upgrade database to new schema on %1 backend.")
607 .arg(ismaster ?
"master" :
"slave"));
626 std::cerr <<
"No setting found for this machine's BackendServerAddr.\n"
627 <<
"Please run mythtv-setup on this machine.\n"
628 <<
"Go to page \"General\" / \"Host Address Backend Setup\" and examine the values.\n"
629 <<
"N.B. The default values are correct for a combined frontend/backend machine.\n"
630 <<
"Press Escape, select \"Save and Exit\" and exit mythtv-setup.\n"
631 <<
"Then start mythbackend again.\n";
639 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Starting up as the master server.");
643 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Running as a slave backend.");
653 bool fatal_error =
false;
654 bool runsched =
setupTVs(ismaster, fatal_error);
704 #ifdef CONFIG_BINDINGS_PYTHON
729 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Use legacy DVBv3 API");
742 LOG(VB_GENERAL, LOG_INFO,
"Main::Registering HttpStatus Extension");
743 be_sd_notify(
"STATUS=Registering HttpStatus Extension");
756 LOG(VB_GENERAL, LOG_CRIT,
757 "Backend exiting, MainServer initialization error.");
768 be_sd_notify(
"STATUS=Sending \"master started\" message");
796 auto styles_css = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/styles.css"); };
797 auto polyfills_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/polyfills.js"); };
798 auto runtime_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/runtime.js"); };
801 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<decltype(PH1)>(PH1),
"apps/backend/index.html"); };
804 {
"/main.js", main_js },
805 {
"/styles.css", styles_css },
806 {
"/polyfills.js", polyfills_js },
807 {
"/runtime.js", runtime_js },
815 exitCode = qApp->exec();
822 qApp->processEvents();
825 LOG(VB_GENERAL, LOG_NOTICE,
"MythBackend exiting");
836 LOG(VB_GENERAL, LOG_NOTICE,
"**********************************************************************");
837 LOG(VB_GENERAL, LOG_NOTICE,
"***** MythBackend starting in webapp only mode for initial setup *****");
838 LOG(VB_GENERAL, LOG_NOTICE,
"***** Use http://localhost:6744 to perform setup *****");
839 LOG(VB_GENERAL, LOG_NOTICE,
"**********************************************************************");
862 auto styles_css = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/styles.css"); };
863 auto polyfills_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/polyfills.js"); };
864 auto runtime_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/runtime.js"); };
867 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<decltype(PH1)>(PH1),
"apps/backend/index.html"); };
870 {
"/main.js", main_js },
871 {
"/styles.css", styles_css },
872 {
"/polyfills.js", polyfills_js },
873 {
"/runtime.js", runtime_js },
881 int exitCode = qApp->exec();
883 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)
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
bool UpgradeTVDatabaseSchema(const bool upgradeAllowed, const bool upgradeIfNoUI, const bool informSystemd)
Called from outside dbcheck.cpp to update the schema.
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.
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.
HouseKeeper * gHousekeeping
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)
@ GENERIC_EXIT_NO_MYTHCONTEXT
No MythContext available.
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.
MythSystemEventHandler * gSysEventHandler
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 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.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
This is the coordinating class of the Recorder Subsystem.
@ GENERIC_EXIT_DB_OUTOFDATE
Database needs upgrade.
int handle_command(const MythBackendCommandLineParser &cmdline)
QString GetHostName(void)
std::vector< HTTPService > HTTPServices
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)
static void RescheduleMatch(uint recordid, uint sourceid, uint mplexid, const QDateTime &maxstarttime, const QString &why)
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)