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); };
20#include <QCoreApplication>
36#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();
327 QString message =
"SET_VERBOSE ";
331 LOG(VB_GENERAL, LOG_INFO,
332 QString(
"Sent '%1' message").arg(message));
335 LOG(VB_GENERAL, LOG_ERR,
336 "Unable to connect to backend, verbose mask unchanged ");
344 QString message =
"SET_LOG_LEVEL ";
348 LOG(VB_GENERAL, LOG_INFO,
349 QString(
"Sent '%1' message").arg(message));
352 LOG(VB_GENERAL, LOG_ERR,
353 "Unable to connect to backend, log level unchanged ");
365 LOG(VB_GENERAL, LOG_ERR,
"Cannot connect to master");
369 std::cout <<
"Retrieving Schedule from Master backend.\n";
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";
404 auto *tempMonitorConnection =
new MythSocket();
405 if (tempMonitorConnection->ConnectToHost(
411 LOG(VB_GENERAL, LOG_ERR,
"Master backend is incompatible with "
412 "this backend.\nCannot become a slave.");
413 tempMonitorConnection->DecrRef();
417 QStringList tempMonitorDone(
"DONE");
419 QStringList tempMonitorAnnounce(QString(
"ANN Monitor %1 0")
421 tempMonitorConnection->SendReceiveStringList(tempMonitorAnnounce);
422 if (tempMonitorAnnounce.empty() ||
423 tempMonitorAnnounce[0] ==
"ERROR")
425 tempMonitorConnection->DecrRef();
426 tempMonitorConnection =
nullptr;
427 if (tempMonitorAnnounce.empty())
429 LOG(VB_GENERAL, LOG_ERR,
LOC +
430 "Failed to open event socket, timeout");
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")));
442 QStringList timeCheck;
443 if (tempMonitorConnection)
445 timeCheck.push_back(
"QUERY_TIME_ZONE");
446 tempMonitorConnection->SendReceiveStringList(timeCheck);
447 tempMonitorConnection->WriteStringList(tempMonitorDone);
449 if (timeCheck.size() < 3)
451 if (tempMonitorConnection)
452 tempMonitorConnection->DecrRef();
458 int timediff = abs(our_time.secsTo(master_time));
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.")
466 if (tempMonitorConnection)
467 tempMonitorConnection->DecrRef();
473 LOG(VB_GENERAL, LOG_WARNING,
474 QString(
"Time difference between the master "
475 "backend and this system is %1 seconds.")
479 if (tempMonitorConnection)
480 tempMonitorConnection->DecrRef();
490 LOG(VB_GENERAL, LOG_WARNING,
LOC +
491 "****** The Housekeeper has been DISABLED with "
492 "the --nohousekeeper option ******");
496 LOG(VB_GENERAL, LOG_WARNING,
LOC +
497 "********** The Scheduler has been DISABLED with "
498 "the --nosched option **********");
502 LOG(VB_GENERAL, LOG_WARNING,
LOC +
503 "********* Auto-Expire has been DISABLED with "
504 "the --noautoexpire option ********");
508 LOG(VB_GENERAL, LOG_WARNING,
LOC +
509 "********* The JobQueue has been DISABLED with "
510 "the --nojobqueue option *********");
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.");
536 LOG(VB_GENERAL, LOG_ERR,
537 QString(
"Couldn't upgrade database to new schema on %1 backend.")
538 .arg(ismaster ?
"master" :
"slave"));
545 LOG(VB_GENERAL, LOG_ERR,
"Exiting as requested.");
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";
581 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Starting up as the master server.");
585 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Running as a slave backend.");
595 bool fatal_error =
false;
596 bool runsched =
setupTVs(ismaster, fatal_error);
647 #ifdef CONFIG_BINDINGS_PYTHON
672 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Use legacy DVBv3 API");
685 LOG(VB_GENERAL, LOG_INFO,
"Main::Registering HttpStatus Extension");
686 be_sd_notify(
"STATUS=Registering HttpStatus Extension");
699 LOG(VB_GENERAL, LOG_CRIT,
700 "Backend exiting, MainServer initialization error.");
711 be_sd_notify(
"STATUS=Sending \"master started\" message");
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"); };
744 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<
decltype(PH1)>(PH1),
"apps/backend/index.html"); };
747 {
"/main.js", main_js },
748 {
"/styles.css", styles_css },
749 {
"/polyfills.js", polyfills_js },
750 {
"/runtime.js", runtime_js },
758 exitCode = qApp->exec();
765 qApp->processEvents();
768 LOG(VB_GENERAL, LOG_NOTICE,
"MythBackend exiting");
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,
"***********************************************************************");
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"); };
810 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<
decltype(PH1)>(PH1),
"apps/backend/index.html"); };
813 {
"/main.js", main_js },
814 {
"/styles.css", styles_css },
815 {
"/polyfills.js", polyfills_js },
816 {
"/runtime.js", runtime_js },
825 be_sd_notify(
"READY=1\nSTATUS=Started in 'Web App only mode'");
826 int exitCode = qApp->exec();
828 be_sd_notify(
"STOPPING=1\nSTATUS='Exiting Web App only mode'");
829 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 RequestTerminate(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
MythCommFlagCommandLineParser cmdline
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.