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"
76#define LOC QString("MythBackend: ")
77#define LOC_WARN QString("MythBackend, Warning: ")
78#define LOC_ERR QString("MythBackend, Error: ")
98 if (!query.
exec(
"UPDATE recorded SET basename = CONCAT(chanid, '_', "
99 "DATE_FORMAT(starttime, '%Y%m%d%H%i00'), '_', "
100 "DATE_FORMAT(endtime, '%Y%m%d%H%i00'), '.nuv') "
101 "WHERE basename = '';"))
107 if (!query.
exec(
"UPDATE channel SET callsign=chanid "
108 "WHERE callsign IS NULL OR callsign='';"))
111 if (query.
exec(
"SELECT MIN(chanid) FROM channel;"))
114 int min_chanid = query.
value(0).toInt();
115 if (!query.
exec(QString(
"UPDATE record SET chanid = %1 "
116 "WHERE chanid IS NULL;").arg(min_chanid)))
125 records_without_station.
prepare(
"SELECT record.chanid,"
126 " channel.callsign FROM record LEFT JOIN channel"
127 " ON record.chanid = channel.chanid WHERE record.station='';");
128 if (records_without_station.
exec())
131 update_record.
prepare(
"UPDATE record SET station = :CALLSIGN"
132 " WHERE chanid = :CHANID;");
133 while (records_without_station.
next())
136 records_without_station.
value(1));
138 records_without_station.
value(0));
139 if (!update_record.
exec())
148 "SELECT cardid, parentid, videodevice, hostname, sourceid "
156 std::vector<unsigned int> cardids;
157 std::vector<QString> hosts;
162 QString videodevice = query.
value(2).toString();
165 QString cidmsg = QString(
"Card[%1](%2)").arg(cardid).arg(videodevice);
169 LOG(VB_GENERAL, LOG_ERR, cidmsg +
170 " does not have a hostname defined.\n"
171 "Please run setup and confirm all of the capture cards.\n");
180 LOG(VB_GENERAL, LOG_WARNING, cidmsg +
181 " does not have a video source");
186 cardids.push_back(cardid);
193 for (
size_t i = 0; i < cardids.size(); i++)
195 if (hosts[i] == localhostname) {
198 new TVRec(cardids[i]);
202 for (
size_t i = 0; i < cardids.size(); i++)
204 uint cardid = cardids[i];
205 const QString& host = hosts[i];
206 QString cidmsg = QString(
"Card %1").arg(cardid);
210 if (host == localhostname)
213 if (tv && tv->
Init())
220 LOG(VB_GENERAL, LOG_ERR,
"Problem with capture cards. " +
221 cidmsg +
" failed init");
231 if (host == localhostname)
234 if (tv && tv->
Init())
241 LOG(VB_GENERAL, LOG_ERR,
"Problem with capture cards. " +
242 cidmsg +
" failed init");
248 auto *enc =
new EncoderLink(cardid,
nullptr, host);
256 LOG(VB_GENERAL, LOG_WARNING,
LOC +
257 "No valid capture cards are defined in the database.");
268 qApp->processEvents();
320 QString message =
"SET_VERBOSE ";
324 LOG(VB_GENERAL, LOG_INFO,
325 QString(
"Sent '%1' message").arg(message));
328 LOG(VB_GENERAL, LOG_ERR,
329 "Unable to connect to backend, verbose mask unchanged ");
337 QString message =
"SET_LOG_LEVEL ";
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, log level unchanged ");
358 LOG(VB_GENERAL, LOG_ERR,
"Cannot connect to master");
362 std::cout <<
"Retrieving Schedule from Master backend.\n";
367 std::cout <<
"Calculating Schedule from database.\n" <<
368 "Inputs, Card IDs, and Conflict info may be invalid "
369 "if you have multiple tuners.\n";
397 auto *tempMonitorConnection =
new MythSocket();
398 if (tempMonitorConnection->ConnectToHost(
404 LOG(VB_GENERAL, LOG_ERR,
"Master backend is incompatible with "
405 "this backend.\nCannot become a slave.");
406 tempMonitorConnection->DecrRef();
410 QStringList tempMonitorDone(
"DONE");
412 QStringList tempMonitorAnnounce(QString(
"ANN Monitor %1 0")
414 tempMonitorConnection->SendReceiveStringList(tempMonitorAnnounce);
415 if (tempMonitorAnnounce.empty() ||
416 tempMonitorAnnounce[0] ==
"ERROR")
418 tempMonitorConnection->DecrRef();
419 tempMonitorConnection =
nullptr;
420 if (tempMonitorAnnounce.empty())
422 LOG(VB_GENERAL, LOG_ERR,
LOC +
423 "Failed to open event socket, timeout");
427 LOG(VB_GENERAL, LOG_ERR,
LOC +
428 "Failed to open event socket" +
429 ((tempMonitorAnnounce.size() >= 2) ?
430 QString(
", error was %1").arg(tempMonitorAnnounce[1]) :
431 QString(
", remote error")));
435 QStringList timeCheck;
436 if (tempMonitorConnection)
438 timeCheck.push_back(
"QUERY_TIME_ZONE");
439 tempMonitorConnection->SendReceiveStringList(timeCheck);
440 tempMonitorConnection->WriteStringList(tempMonitorDone);
442 if (timeCheck.size() < 3)
444 if (tempMonitorConnection)
445 tempMonitorConnection->DecrRef();
451 int timediff = abs(our_time.secsTo(master_time));
455 LOG(VB_GENERAL, LOG_ERR,
456 QString(
"Current time on the master backend differs by "
457 "%1 seconds from time on this system. Exiting.")
459 if (tempMonitorConnection)
460 tempMonitorConnection->DecrRef();
466 LOG(VB_GENERAL, LOG_WARNING,
467 QString(
"Time difference between the master "
468 "backend and this system is %1 seconds.")
472 if (tempMonitorConnection)
473 tempMonitorConnection->DecrRef();
483 LOG(VB_GENERAL, LOG_WARNING,
LOC +
484 "****** The Housekeeper has been DISABLED with "
485 "the --nohousekeeper option ******");
489 LOG(VB_GENERAL, LOG_WARNING,
LOC +
490 "********** The Scheduler has been DISABLED with "
491 "the --nosched option **********");
495 LOG(VB_GENERAL, LOG_WARNING,
LOC +
496 "********* Auto-Expire has been DISABLED with "
497 "the --noautoexpire option ********");
501 LOG(VB_GENERAL, LOG_WARNING,
LOC +
502 "********* The JobQueue has been DISABLED with "
503 "the --nojobqueue option *********");
517 LOG(VB_GENERAL, LOG_ERR,
518 "MySQL time zone support is missing. "
519 "Please install it and try again. "
520 "See 'mysql_tzinfo_to_sql' for assistance.");
529 LOG(VB_GENERAL, LOG_ERR,
530 QString(
"Couldn't upgrade database to new schema on %1 backend.")
531 .arg(ismaster ?
"master" :
"slave"));
538 LOG(VB_GENERAL, LOG_ERR,
"Exiting as requested.");
563 std::cerr <<
"No setting found for this machine's BackendServerAddr.\n"
564 <<
"MythBackend starting in Web App only mode for initial setup.\n"
565 <<
"Use http://<yourBackend>:6544 to perform setup.\n";
574 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Starting up as the master server.");
578 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Running as a slave backend.");
588 bool fatal_error =
false;
589 bool runsched =
setupTVs(ismaster, fatal_error);
640 #ifdef CONFIG_BINDINGS_PYTHON
665 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Use legacy DVBv3 API");
678 LOG(VB_GENERAL, LOG_INFO,
"Main::Registering HttpStatus Extension");
679 be_sd_notify(
"STATUS=Registering HttpStatus Extension");
692 LOG(VB_GENERAL, LOG_CRIT,
693 "Backend exiting, MainServer initialization error.");
704 be_sd_notify(
"STATUS=Sending \"master started\" message");
732 auto styles_css = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/styles.css"); };
733 auto polyfills_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/polyfills.js"); };
734 auto runtime_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/runtime.js"); };
737 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<
decltype(PH1)>(PH1),
"apps/backend/index.html"); };
740 {
"/main.js", main_js },
741 {
"/styles.css", styles_css },
742 {
"/polyfills.js", polyfills_js },
743 {
"/runtime.js", runtime_js },
751 exitCode = qApp->exec();
758 qApp->processEvents();
761 LOG(VB_GENERAL, LOG_NOTICE,
"MythBackend exiting");
772 LOG(VB_GENERAL, LOG_NOTICE,
"***********************************************************************");
773 LOG(VB_GENERAL, LOG_NOTICE,
"***** MythBackend starting in Web App only mode for initial setup *****");
774 LOG(VB_GENERAL, LOG_NOTICE,
"***** Use http://<yourBackend>:6544 to perform setup *****");
775 LOG(VB_GENERAL, LOG_NOTICE,
"***********************************************************************");
798 auto styles_css = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/styles.css"); };
799 auto polyfills_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/polyfills.js"); };
800 auto runtime_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/runtime.js"); };
803 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<
decltype(PH1)>(PH1),
"apps/backend/index.html"); };
806 {
"/main.js", main_js },
807 {
"/styles.css", styles_css },
808 {
"/polyfills.js", polyfills_js },
809 {
"/runtime.js", runtime_js },
818 be_sd_notify(
"READY=1\nSTATUS=Started in 'Web App only mode'");
819 int exitCode = qApp->exec();
821 be_sd_notify(
"STOPPING=1\nSTATUS='Exiting Web App only mode'");
822 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