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); };
21#include <QCoreApplication>
37#include "libmythbase/mythversion.h"
77#define LOC QString("MythBackend: ")
78#define LOC_WARN QString("MythBackend, Warning: ")
79#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)))
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())
132 update_record.
prepare(
"UPDATE record SET station = :CALLSIGN"
133 " WHERE chanid = :CHANID;");
134 while (records_without_station.
next())
137 records_without_station.
value(1));
139 records_without_station.
value(0));
140 if (!update_record.
exec())
149 "SELECT cardid, parentid, videodevice, hostname, sourceid "
157 std::vector<unsigned int> cardids;
158 std::vector<QString> hosts;
163 QString videodevice = query.
value(2).toString();
166 QString cidmsg = QString(
"Card[%1](%2)").arg(cardid).arg(videodevice);
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");
181 LOG(VB_GENERAL, LOG_WARNING, cidmsg +
182 " does not have a video source");
187 cardids.push_back(cardid);
194 for (
size_t i = 0; i < cardids.size(); i++)
196 if (hosts[i] == localhostname) {
199 new TVRec(cardids[i]);
203 for (
size_t i = 0; i < cardids.size(); i++)
205 uint cardid = cardids[i];
206 const QString& host = hosts[i];
207 QString cidmsg = QString(
"Card %1").arg(cardid);
211 if (host == localhostname)
214 if (tv && tv->
Init())
221 LOG(VB_GENERAL, LOG_ERR,
"Problem with capture cards. " +
222 cidmsg +
" failed init");
232 if (host == localhostname)
235 if (tv && tv->
Init())
242 LOG(VB_GENERAL, LOG_ERR,
"Problem with capture cards. " +
243 cidmsg +
" failed init");
249 auto *enc =
new EncoderLink(cardid,
nullptr, host);
257 LOG(VB_GENERAL, LOG_WARNING,
LOC +
258 "No valid capture cards are defined in the database.");
269 qApp->processEvents();
321 QString message =
"SET_VERBOSE ";
325 LOG(VB_GENERAL, LOG_INFO,
326 QString(
"Sent '%1' message").arg(message));
329 LOG(VB_GENERAL, LOG_ERR,
330 "Unable to connect to backend, verbose mask unchanged ");
338 QString message =
"SET_LOG_LEVEL ";
342 LOG(VB_GENERAL, LOG_INFO,
343 QString(
"Sent '%1' message").arg(message));
346 LOG(VB_GENERAL, LOG_ERR,
347 "Unable to connect to backend, log level unchanged ");
359 LOG(VB_GENERAL, LOG_ERR,
"Cannot connect to master");
363 std::cout <<
"Retrieving Schedule from Master backend.\n";
368 std::cout <<
"Calculating Schedule from database.\n" <<
369 "Inputs, Card IDs, and Conflict info may be invalid "
370 "if you have multiple tuners.\n";
398 auto *tempMonitorConnection =
new MythSocket();
399 if (tempMonitorConnection->ConnectToHost(
405 LOG(VB_GENERAL, LOG_ERR,
"Master backend is incompatible with "
406 "this backend.\nCannot become a slave.");
407 tempMonitorConnection->DecrRef();
411 QStringList tempMonitorDone(
"DONE");
413 QStringList tempMonitorAnnounce(QString(
"ANN Monitor %1 0")
415 tempMonitorConnection->SendReceiveStringList(tempMonitorAnnounce);
416 if (tempMonitorAnnounce.empty() ||
417 tempMonitorAnnounce[0] ==
"ERROR")
419 tempMonitorConnection->DecrRef();
420 tempMonitorConnection =
nullptr;
421 if (tempMonitorAnnounce.empty())
423 LOG(VB_GENERAL, LOG_ERR,
LOC +
424 "Failed to open event socket, timeout");
428 LOG(VB_GENERAL, LOG_ERR,
LOC +
429 "Failed to open event socket" +
430 ((tempMonitorAnnounce.size() >= 2) ?
431 QString(
", error was %1").arg(tempMonitorAnnounce[1]) :
432 QString(
", remote error")));
436 QStringList timeCheck;
437 if (tempMonitorConnection)
439 timeCheck.push_back(
"QUERY_TIME_ZONE");
440 tempMonitorConnection->SendReceiveStringList(timeCheck);
441 tempMonitorConnection->WriteStringList(tempMonitorDone);
443 if (timeCheck.size() < 3)
445 if (tempMonitorConnection)
446 tempMonitorConnection->DecrRef();
452 int timediff = abs(our_time.secsTo(master_time));
456 LOG(VB_GENERAL, LOG_ERR,
457 QString(
"Current time on the master backend differs by "
458 "%1 seconds from time on this system. Exiting.")
460 if (tempMonitorConnection)
461 tempMonitorConnection->DecrRef();
467 LOG(VB_GENERAL, LOG_WARNING,
468 QString(
"Time difference between the master "
469 "backend and this system is %1 seconds.")
473 if (tempMonitorConnection)
474 tempMonitorConnection->DecrRef();
484 LOG(VB_GENERAL, LOG_WARNING,
LOC +
485 "****** The Housekeeper has been DISABLED with "
486 "the --nohousekeeper option ******");
490 LOG(VB_GENERAL, LOG_WARNING,
LOC +
491 "********** The Scheduler has been DISABLED with "
492 "the --nosched option **********");
496 LOG(VB_GENERAL, LOG_WARNING,
LOC +
497 "********* Auto-Expire has been DISABLED with "
498 "the --noautoexpire option ********");
502 LOG(VB_GENERAL, LOG_WARNING,
LOC +
503 "********* The JobQueue has been DISABLED with "
504 "the --nojobqueue option *********");
518 LOG(VB_GENERAL, LOG_ERR,
519 "MySQL time zone support is missing. "
520 "Please install it and try again. "
521 "See 'mysql_tzinfo_to_sql' for assistance.");
530 LOG(VB_GENERAL, LOG_ERR,
531 QString(
"Couldn't upgrade database to new schema on %1 backend.")
532 .arg(ismaster ?
"master" :
"slave"));
539 LOG(VB_GENERAL, LOG_ERR,
"Exiting as requested.");
564 std::cerr <<
"No setting found for this machine's BackendServerAddr.\n"
565 <<
"MythBackend starting in Web App only mode for initial setup.\n"
566 <<
"Use http://<yourBackend>:6544 to perform setup.\n";
575 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Starting up as the master server.");
579 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Running as a slave backend.");
589 bool fatal_error =
false;
590 bool runsched =
setupTVs(ismaster, fatal_error);
641 #ifdef CONFIG_BINDINGS_PYTHON
666 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Use legacy DVBv3 API");
679 LOG(VB_GENERAL, LOG_INFO,
"Main::Registering HttpStatus Extension");
680 be_sd_notify(
"STATUS=Registering HttpStatus Extension");
693 LOG(VB_GENERAL, LOG_CRIT,
694 "Backend exiting, MainServer initialization error.");
705 be_sd_notify(
"STATUS=Sending \"master started\" message");
733 auto styles_css = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/styles.css"); };
734 auto polyfills_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/polyfills.js"); };
735 auto runtime_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/runtime.js"); };
738 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<
decltype(PH1)>(PH1),
"apps/backend/index.html"); };
741 {
"/main.js", main_js },
742 {
"/styles.css", styles_css },
743 {
"/polyfills.js", polyfills_js },
744 {
"/runtime.js", runtime_js },
752 exitCode = qApp->exec();
759 qApp->processEvents();
762 LOG(VB_GENERAL, LOG_NOTICE,
"MythBackend exiting");
773 LOG(VB_GENERAL, LOG_NOTICE,
"***********************************************************************");
774 LOG(VB_GENERAL, LOG_NOTICE,
"***** MythBackend starting in Web App only mode for initial setup *****");
775 LOG(VB_GENERAL, LOG_NOTICE,
"***** Use http://<yourBackend>:6544 to perform setup *****");
776 LOG(VB_GENERAL, LOG_NOTICE,
"***********************************************************************");
799 auto styles_css = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/styles.css"); };
800 auto polyfills_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/polyfills.js"); };
801 auto runtime_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/runtime.js"); };
804 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<
decltype(PH1)>(PH1),
"apps/backend/index.html"); };
807 {
"/main.js", main_js },
808 {
"/styles.css", styles_css },
809 {
"/polyfills.js", polyfills_js },
810 {
"/runtime.js", runtime_js },
819 be_sd_notify(
"READY=1\nSTATUS=Started in 'Web App only mode'");
820 int exitCode = qApp->exec();
822 be_sd_notify(
"STOPPING=1\nSTATUS='Exiting Web App only mode'");
823 LOG(VB_GENERAL, LOG_NOTICE,
"MythBackend Web App only mode exiting");
QMap< int, EncoderLink * > gTVList
BackendContext * gBackendContext
Used to expire recordings to make space for new recordings.
void PrintExpireList(const QString &expHost="ALL")
Prints a summary of the files that can be deleted.
static void UpdateChannelGroups(void)
static bool CheckTimeZoneSupport(void)
Check if MySQL has working timz zone support.
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.
Manages registered HouseKeeperTasks and queues tasks for operation.
void RegisterTask(HouseKeeperTask *task)
void RegisterExtension(HttpServerExtension *pExtension)
void SetMainServer(MainServer *mainServer)
QSqlQuery wrapper that fetches a DB connection from the connection pool.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
QVariant value(int i) const
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
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.
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)
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.
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)
void PrintList(bool onlyFutureRecordings=false)
void DisableScheduling(void)
void SetExpirer(AutoExpire *autoExpirer)
void FillRecordListFromMaster(void)
static void CheckAllStorageGroupDirs(void)
This is the coordinating class of the Recorder Subsystem.
bool Init(void)
Performs instance initialization, returns true on success.
static TVRec * GetTVRec(uint inputid)
static QReadWriteLock s_inputsLock
static QMap< uint, TVRec * > s_inputs
static TaskQueue * Instance()
HttpServer * GetHttpServer()
static WebOnlyStartup s_WebOnlyStartup
bool UpgradeTVDatabaseSchema(const bool upgradeAllowed, const bool upgradeIfNoUI, const bool informSystemd)
Called from outside dbcheck.cpp to update the schema.
@ GENERIC_EXIT_CONNECT_ERROR
Can't connect to master backend.
@ GENERIC_EXIT_INVALID_TIME
Invalid time.
@ GENERIC_EXIT_OK
Exited with no error.
@ GENERIC_EXIT_SETUP_ERROR
Incorrectly setup system.
@ GENERIC_EXIT_SOCKET_ERROR
Socket error.
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()
static MythSystemEventHandler * gSysEventHandler
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
std::vector< HTTPHandler > HTTPHandlers
std::vector< HTTPService > HTTPServices
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
MythCommFlagCommandLineParser cmdline