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: ")
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)))
121 records_without_station.
prepare(
"SELECT record.chanid,"
122 " channel.callsign FROM record LEFT JOIN channel"
123 " ON record.chanid = channel.chanid WHERE record.station='';");
124 if (records_without_station.
exec())
127 update_record.
prepare(
"UPDATE record SET station = :CALLSIGN"
128 " WHERE chanid = :CHANID;");
129 while (records_without_station.
next())
132 records_without_station.
value(1));
134 records_without_station.
value(0));
135 if (!update_record.
exec())
150 "SELECT cardid, parentid, videodevice, hostname, sourceid "
158 std::vector<unsigned int> cardids;
159 std::vector<QString> hosts;
164 QString videodevice = query.
value(2).toString();
167 QString cidmsg = QString(
"Card[%1](%2)").arg(cardid).arg(videodevice);
171 LOG(VB_GENERAL, LOG_ERR, cidmsg +
172 " does not have a hostname defined.\n"
173 "Please run setup and confirm all of the capture cards.\n");
180 if (parentid == 0 && !retry)
182 LOG(VB_GENERAL, LOG_WARNING, cidmsg +
183 " does not have a video source");
194 cardids.push_back(cardid);
201 for (
size_t i = 0; i < cardids.size(); i++)
203 if (hosts[i] == localhostname) {
206 new TVRec(cardids[i]);
210 for (
size_t i = 0; i < cardids.size(); i++)
212 uint cardid = cardids[i];
213 const QString& host = hosts[i];
214 QString cidmsg = QString(
"Card %1").arg(cardid);
218 if (host == localhostname)
221 if (tv && tv->
Init())
228 LOG(VB_GENERAL, LOG_ERR,
"Problem with capture cards. " +
229 cidmsg +
" failed init");
239 if (host == localhostname)
242 if (tv && tv->
Init())
249 LOG(VB_GENERAL, LOG_ERR,
"Problem with capture cards. " +
250 cidmsg +
" failed init");
256 auto *enc =
new EncoderLink(cardid,
nullptr, host);
264 LOG(VB_GENERAL, LOG_WARNING,
LOC +
265 "No valid capture cards are defined in the database.");
276 qApp->processEvents();
328 QString message =
"SET_VERBOSE ";
332 LOG(VB_GENERAL, LOG_INFO,
333 QString(
"Sent '%1' message").arg(message));
336 LOG(VB_GENERAL, LOG_ERR,
337 "Unable to connect to backend, verbose mask unchanged ");
345 QString message =
"SET_LOG_LEVEL ";
349 LOG(VB_GENERAL, LOG_INFO,
350 QString(
"Sent '%1' message").arg(message));
353 LOG(VB_GENERAL, LOG_ERR,
354 "Unable to connect to backend, log level unchanged ");
366 LOG(VB_GENERAL, LOG_ERR,
"Cannot connect to master");
370 std::cout <<
"Retrieving Schedule from Master backend.\n";
375 std::cout <<
"Calculating Schedule from database.\n" <<
376 "Inputs, Card IDs, and Conflict info may be invalid "
377 "if you have multiple tuners.\n";
405 auto *tempMonitorConnection =
new MythSocket();
406 if (tempMonitorConnection->ConnectToHost(
412 LOG(VB_GENERAL, LOG_ERR,
"Master backend is incompatible with "
413 "this backend.\nCannot become a slave.");
414 tempMonitorConnection->DecrRef();
418 QStringList tempMonitorDone(
"DONE");
420 QStringList tempMonitorAnnounce(QString(
"ANN Monitor %1 0")
422 tempMonitorConnection->SendReceiveStringList(tempMonitorAnnounce);
423 if (tempMonitorAnnounce.empty() ||
424 tempMonitorAnnounce[0] ==
"ERROR")
426 tempMonitorConnection->DecrRef();
427 tempMonitorConnection =
nullptr;
428 if (tempMonitorAnnounce.empty())
430 LOG(VB_GENERAL, LOG_ERR,
LOC +
431 "Failed to open event socket, timeout");
435 LOG(VB_GENERAL, LOG_ERR,
LOC +
436 "Failed to open event socket" +
437 ((tempMonitorAnnounce.size() >= 2) ?
438 QString(
", error was %1").arg(tempMonitorAnnounce[1]) :
439 QString(
", remote error")));
443 QStringList timeCheck;
444 if (tempMonitorConnection)
446 timeCheck.push_back(
"QUERY_TIME_ZONE");
447 tempMonitorConnection->SendReceiveStringList(timeCheck);
448 tempMonitorConnection->WriteStringList(tempMonitorDone);
450 if (timeCheck.size() < 3)
452 if (tempMonitorConnection)
453 tempMonitorConnection->DecrRef();
459 int timediff = abs(our_time.secsTo(master_time));
463 LOG(VB_GENERAL, LOG_ERR,
464 QString(
"Current time on the master backend differs by "
465 "%1 seconds from time on this system. Exiting.")
467 if (tempMonitorConnection)
468 tempMonitorConnection->DecrRef();
474 LOG(VB_GENERAL, LOG_WARNING,
475 QString(
"Time difference between the master "
476 "backend and this system is %1 seconds.")
480 if (tempMonitorConnection)
481 tempMonitorConnection->DecrRef();
491 LOG(VB_GENERAL, LOG_WARNING,
LOC +
492 "****** The Housekeeper has been DISABLED with "
493 "the --nohousekeeper option ******");
497 LOG(VB_GENERAL, LOG_WARNING,
LOC +
498 "********** The Scheduler has been DISABLED with "
499 "the --nosched option **********");
503 LOG(VB_GENERAL, LOG_WARNING,
LOC +
504 "********* Auto-Expire has been DISABLED with "
505 "the --noautoexpire option ********");
509 LOG(VB_GENERAL, LOG_WARNING,
LOC +
510 "********* The JobQueue has been DISABLED with "
511 "the --nojobqueue option *********");
525 LOG(VB_GENERAL, LOG_ERR,
526 "MySQL time zone support is missing. "
527 "Please install it and try again. "
528 "See 'mysql_tzinfo_to_sql' for assistance.");
537 LOG(VB_GENERAL, LOG_ERR,
538 QString(
"Couldn't upgrade database to new schema on %1 backend.")
539 .arg(ismaster ?
"master" :
"slave"));
546 LOG(VB_GENERAL, LOG_ERR,
"Exiting as requested.");
571 std::cerr <<
"No setting found for this machine's BackendServerAddr.\n"
572 <<
"MythBackend starting in Web App only mode for initial setup.\n"
573 <<
"Use http://<yourBackend>:6544 to perform setup.\n";
582 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Starting up as the master server.");
586 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Running as a slave backend.");
648 #ifdef CONFIG_BINDINGS_PYTHON
674 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Use legacy DVBv3 API");
687 LOG(VB_GENERAL, LOG_INFO,
"Main::Registering HttpStatus Extension");
688 be_sd_notify(
"STATUS=Registering HttpStatus Extension");
701 LOG(VB_GENERAL, LOG_CRIT,
702 "Backend exiting, MainServer initialization error.");
713 be_sd_notify(
"STATUS=Sending \"master started\" message");
748 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<
decltype(PH1)>(PH1),
"apps/backend/index.html"); };
762 exitCode = qApp->exec();
769 qApp->processEvents();
772 LOG(VB_GENERAL, LOG_NOTICE,
"MythBackend exiting");
783 LOG(VB_GENERAL, LOG_NOTICE,
"***********************************************************************");
784 LOG(VB_GENERAL, LOG_NOTICE,
"***** MythBackend starting in Web App only mode for initial setup *****");
785 LOG(VB_GENERAL, LOG_NOTICE,
"***** Use http://<yourBackend>:6544 to perform setup *****");
786 LOG(VB_GENERAL, LOG_NOTICE,
"***********************************************************************");
809 auto styles_css = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/styles.css"); };
810 auto polyfills_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/polyfills.js"); };
811 auto runtime_js = [](
auto && PH1) {
return MythHTTPRewrite::RewriteFile(std::forward<
decltype(PH1)>(PH1),
"apps/backend/runtime.js"); };
814 auto root = [](
auto && PH1) {
return MythHTTPRoot::RedirectRoot(std::forward<
decltype(PH1)>(PH1),
"apps/backend/index.html"); };
817 {
"/main.js", main_js },
818 {
"/styles.css", styles_css },
819 {
"/polyfills.js", polyfills_js },
820 {
"/runtime.js", runtime_js },
829 be_sd_notify(
"READY=1\nSTATUS=Started in 'Web App only mode'");
830 int exitCode = qApp->exec();
832 be_sd_notify(
"STOPPING=1\nSTATUS='Exiting Web App only mode'");
833 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_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
void print_warnings(const MythBackendCommandLineParser &cmdline)
static void be_sd_notify(const char *)
bool createTVRecorders(bool ismaster, bool retry)
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