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"
75 #define LOC QString("MythBackend: ")
76 #define LOC_WARN QString("MythBackend, Warning: ")
77 #define LOC_ERR QString("MythBackend, Error: ")
97 if (!query.
exec(
"UPDATE recorded SET basename = CONCAT(chanid, '_', "
98 "DATE_FORMAT(starttime, '%Y%m%d%H%i00'), '_', "
99 "DATE_FORMAT(endtime, '%Y%m%d%H%i00'), '.nuv') "
100 "WHERE basename = '';"))
106 if (!query.
exec(
"UPDATE channel SET callsign=chanid "
107 "WHERE callsign IS NULL OR callsign='';"))
110 if (query.
exec(
"SELECT MIN(chanid) FROM channel;"))
113 int min_chanid = query.
value(0).toInt();
114 if (!query.
exec(QString(
"UPDATE record SET chanid = %1 "
115 "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 const 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();
325 QString message =
"SET_VERBOSE ";
329 LOG(VB_GENERAL, LOG_INFO,
330 QString(
"Sent '%1' message").arg(message));
333 LOG(VB_GENERAL, LOG_ERR,
334 "Unable to connect to backend, verbose mask unchanged ");
342 QString message =
"SET_LOG_LEVEL ";
346 LOG(VB_GENERAL, LOG_INFO,
347 QString(
"Sent '%1' message").arg(message));
350 LOG(VB_GENERAL, LOG_ERR,
351 "Unable to connect to backend, log level unchanged ");
363 LOG(VB_GENERAL, LOG_ERR,
"Cannot connect to master");
367 std::cout <<
"Retrieving Schedule from Master backend.\n";
372 std::cout <<
"Calculating Schedule from database.\n" <<
373 "Inputs, Card IDs, and Conflict info may be invalid "
374 "if you have multiple tuners.\n";
402 auto *tempMonitorConnection =
new MythSocket();
403 if (tempMonitorConnection->ConnectToHost(
409 LOG(VB_GENERAL, LOG_ERR,
"Master backend is incompatible with "
410 "this backend.\nCannot become a slave.");
411 tempMonitorConnection->DecrRef();
415 QStringList tempMonitorDone(
"DONE");
417 QStringList tempMonitorAnnounce(QString(
"ANN Monitor %1 0")
419 tempMonitorConnection->SendReceiveStringList(tempMonitorAnnounce);
420 if (tempMonitorAnnounce.empty() ||
421 tempMonitorAnnounce[0] ==
"ERROR")
423 tempMonitorConnection->DecrRef();
424 tempMonitorConnection =
nullptr;
425 if (tempMonitorAnnounce.empty())
427 LOG(VB_GENERAL, LOG_ERR,
LOC +
428 "Failed to open event socket, timeout");
432 LOG(VB_GENERAL, LOG_ERR,
LOC +
433 "Failed to open event socket" +
434 ((tempMonitorAnnounce.size() >= 2) ?
435 QString(
", error was %1").arg(tempMonitorAnnounce[1]) :
436 QString(
", remote error")));
440 QStringList timeCheck;
441 if (tempMonitorConnection)
443 timeCheck.push_back(
"QUERY_TIME_ZONE");
444 tempMonitorConnection->SendReceiveStringList(timeCheck);
445 tempMonitorConnection->WriteStringList(tempMonitorDone);
447 if (timeCheck.size() < 3)
449 if (tempMonitorConnection)
450 tempMonitorConnection->DecrRef();
456 int timediff = abs(our_time.secsTo(master_time));
460 LOG(VB_GENERAL, LOG_ERR,
461 QString(
"Current time on the master backend differs by "
462 "%1 seconds from time on this system. Exiting.")
464 if (tempMonitorConnection)
465 tempMonitorConnection->DecrRef();
471 LOG(VB_GENERAL, LOG_WARNING,
472 QString(
"Time difference between the master "
473 "backend and this system is %1 seconds.")
477 if (tempMonitorConnection)
478 tempMonitorConnection->DecrRef();
488 LOG(VB_GENERAL, LOG_WARNING,
LOC +
489 "****** The Housekeeper has been DISABLED with "
490 "the --nohousekeeper option ******");
494 LOG(VB_GENERAL, LOG_WARNING,
LOC +
495 "********** The Scheduler has been DISABLED with "
496 "the --nosched option **********");
500 LOG(VB_GENERAL, LOG_WARNING,
LOC +
501 "********* Auto-Expire has been DISABLED with "
502 "the --noautoexpire option ********");
506 LOG(VB_GENERAL, LOG_WARNING,
LOC +
507 "********* The JobQueue has been DISABLED with "
508 "the --nojobqueue option *********");
522 LOG(VB_GENERAL, LOG_ERR,
523 "MySQL time zone support is missing. "
524 "Please install it and try again. "
525 "See 'mysql_tzinfo_to_sql' for assistance.");
534 LOG(VB_GENERAL, LOG_ERR,
535 QString(
"Couldn't upgrade database to new schema on %1 backend.")
536 .arg(ismaster ?
"master" :
"slave"));
543 LOG(VB_GENERAL, LOG_ERR,
"Exiting as requested.");
568 std::cerr <<
"No setting found for this machine's BackendServerAddr.\n"
569 <<
"MythBackend starting in Web App only mode for initial setup.\n"
570 <<
"Use http://<yourBackend>:6544 to perform setup.\n";
579 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Starting up as the master server.");
583 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Running as a slave backend.");
593 bool fatal_error =
false;
594 bool runsched =
setupTVs(ismaster, fatal_error);
645 #ifdef CONFIG_BINDINGS_PYTHON
670 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Use legacy DVBv3 API");
683 LOG(VB_GENERAL, LOG_INFO,
"Main::Registering HttpStatus Extension");
684 be_sd_notify(
"STATUS=Registering HttpStatus Extension");
697 LOG(VB_GENERAL, LOG_CRIT,
698 "Backend exiting, MainServer initialization error.");
709 be_sd_notify(
"STATUS=Sending \"master started\" message");
737 auto styles_css = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/styles.css"); };
738 auto polyfills_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/polyfills.js"); };
739 auto runtime_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/runtime.js"); };
742 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<decltype(PH1)>(PH1),
"apps/backend/index.html"); };
745 {
"/main.js", main_js },
746 {
"/styles.css", styles_css },
747 {
"/polyfills.js", polyfills_js },
748 {
"/runtime.js", runtime_js },
756 exitCode = qApp->exec();
763 qApp->processEvents();
766 LOG(VB_GENERAL, LOG_NOTICE,
"MythBackend exiting");
777 LOG(VB_GENERAL, LOG_NOTICE,
"***********************************************************************");
778 LOG(VB_GENERAL, LOG_NOTICE,
"***** MythBackend starting in Web App only mode for initial setup *****");
779 LOG(VB_GENERAL, LOG_NOTICE,
"***** Use http://<yourBackend>:6544 to perform setup *****");
780 LOG(VB_GENERAL, LOG_NOTICE,
"***********************************************************************");
803 auto styles_css = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/styles.css"); };
804 auto polyfills_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/polyfills.js"); };
805 auto runtime_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<decltype(PH1)>(PH1),
"apps/backend/runtime.js"); };
808 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<decltype(PH1)>(PH1),
"apps/backend/index.html"); };
811 {
"/main.js", main_js },
812 {
"/styles.css", styles_css },
813 {
"/polyfills.js", polyfills_js },
814 {
"/runtime.js", runtime_js },
823 be_sd_notify(
"READY=1\nSTATUS=Started in 'Web App only mode'");
824 int exitCode = qApp->exec();
826 be_sd_notify(
"STOPPING=1\nSTATUS='Exiting Web App only mode'");
827 LOG(VB_GENERAL, LOG_NOTICE,
"MythBackend Web App only mode 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)
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.
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_)
void RegisterTask(HouseKeeperTask *task)
BackendContext * gBackendContext
void SetMainServer(MainServer *mainServer)
static WebOnlyStartup s_WebOnlyStartup
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.
@ GENERIC_EXIT_OK
Exited with no error.
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)
static void DBError(const QString &where, const MSqlQuery &query)
void SetExpirer(AutoExpire *autoExpirer)
@ GENERIC_EXIT_CONNECT_ERROR
Can't connect to master backend.
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,...
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
@ GENERIC_EXIT_SETUP_ERROR
Incorrectly setup system.
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
@ GENERIC_EXIT_INVALID_TIME
Invalid time.
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)
@ GENERIC_EXIT_SOCKET_ERROR
Socket error.
static void CheckAllStorageGroupDirs(void)
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)