1
0
Fork 0
mirror of https://github.com/polybar/polybar.git synced 2024-11-11 13:50:56 -05:00

fix(mpd): Handle broken connections

This commit is contained in:
Michael Carlberg 2017-01-13 13:02:51 +01:00
parent 22140f7db9
commit 15f880eba4
4 changed files with 62 additions and 55 deletions

View file

@ -3,6 +3,7 @@
#include <mpd/client.h> #include <mpd/client.h>
#include <stdlib.h> #include <stdlib.h>
#include <chrono> #include <chrono>
#include <csignal>
#include "common.hpp" #include "common.hpp"
#include "errors.hpp" #include "errors.hpp"
@ -15,6 +16,8 @@ class logger;
namespace chrono = std::chrono; namespace chrono = std::chrono;
namespace mpd { namespace mpd {
extern sig_atomic_t g_connection_closed;
DEFINE_ERROR(mpd_exception); DEFINE_ERROR(mpd_exception);
DEFINE_CHILD_ERROR(client_error, mpd_exception); DEFINE_CHILD_ERROR(client_error, mpd_exception);
DEFINE_CHILD_ERROR(server_error, mpd_exception); DEFINE_CHILD_ERROR(server_error, mpd_exception);
@ -78,6 +81,7 @@ namespace mpd {
public: public:
explicit mpdconnection( explicit mpdconnection(
const logger& logger, string host, unsigned int port = 6600, string password = "", unsigned int timeout = 15); const logger& logger, string host, unsigned int port = 6600, string password = "", unsigned int timeout = 15);
~mpdconnection();
void connect(); void connect();
void disconnect(); void disconnect();
@ -114,6 +118,8 @@ namespace mpd {
const logger& m_log; const logger& m_log;
mpd_connection_t m_connection{}; mpd_connection_t m_connection{};
struct sigaction m_signal_action {};
bool m_listactive = false; bool m_listactive = false;
bool m_idle = false; bool m_idle = false;
int m_fd = -1; int m_fd = -1;

View file

@ -10,8 +10,6 @@ POLYBAR_NS
using namespace mpd; using namespace mpd;
namespace chrono = std::chrono;
namespace modules { namespace modules {
class mpd_module : public event_module<mpd_module>, public input_handler { class mpd_module : public event_module<mpd_module>, public input_handler {
public: public:
@ -70,9 +68,11 @@ namespace modules {
chrono::system_clock::time_point m_lastsync{}; chrono::system_clock::time_point m_lastsync{};
float m_synctime{1.0f}; float m_synctime{1.0f};
int m_quick_attempts{0};
// This flag is used to let thru a broadcast once every time // This flag is used to let thru a broadcast once every time
// the connection state changes // the connection state changes
mpd::connection_state m_statebroadcasted{mpd::connection_state::NONE}; connection_state m_statebroadcasted{connection_state::NONE};
progressbar_t m_bar_progress; progressbar_t m_bar_progress;
iconset_t m_icons; iconset_t m_icons;

View file

@ -1,35 +1,43 @@
#include <cassert> #include <cassert>
#include <csignal>
#include <thread> #include <thread>
#include <utility> #include <utility>
#include "adapters/mpd.hpp" #include "adapters/mpd.hpp"
#include "components/logger.hpp" #include "components/logger.hpp"
#include "utils/math.hpp" #include "utils/math.hpp"
#include "utils/string.hpp"
POLYBAR_NS POLYBAR_NS
namespace mpd { namespace mpd {
sig_atomic_t g_connection_closed = 0;
void g_mpd_signal_handler(int signum) {
if (signum == SIGPIPE) {
g_connection_closed = 1;
}
}
void check_connection(mpd_connection* conn) { void check_connection(mpd_connection* conn) {
if (conn == nullptr) { if (g_connection_closed) {
throw client_error("Not connected to MPD server", MPD_ERROR_STATE); g_connection_closed = 0;
throw server_error("Connection closed (broken pipe)");
} else if (conn == nullptr) {
throw client_error("Not connected to server", MPD_ERROR_STATE);
} }
} }
void check_errors(mpd_connection* conn) { void check_errors(mpd_connection* conn) {
mpd_error code = mpd_connection_get_error(conn); check_connection(conn);
switch (mpd_connection_get_error(conn)) {
if (code == MPD_ERROR_SUCCESS) { case MPD_ERROR_SUCCESS:
return; return;
} case MPD_ERROR_SERVER:
mpd_connection_clear_error(conn);
auto msg = mpd_connection_get_error_message(conn); throw server_error(mpd_connection_get_error_message(conn), mpd_connection_get_server_error(conn));
default:
if (code == MPD_ERROR_SERVER) { mpd_connection_clear_error(conn);
mpd_connection_clear_error(conn); throw client_error(mpd_connection_get_error_message(conn), mpd_connection_get_error(conn));
throw server_error(msg, mpd_connection_get_server_error(conn));
} else {
mpd_connection_clear_error(conn);
throw client_error(msg, code);
} }
} }
@ -70,28 +78,19 @@ namespace mpd {
string mpdsong::get_album() { string mpdsong::get_album() {
assert(m_song); assert(m_song);
auto tag = mpd_song_get_tag(m_song.get(), MPD_TAG_ALBUM, 0); auto tag = mpd_song_get_tag(m_song.get(), MPD_TAG_ALBUM, 0);
if (tag == nullptr) { return string{tag != nullptr ? tag : ""};
return "";
}
return string{tag};
} }
string mpdsong::get_date() { string mpdsong::get_date() {
assert(m_song); assert(m_song);
auto tag = mpd_song_get_tag(m_song.get(), MPD_TAG_DATE, 0); auto tag = mpd_song_get_tag(m_song.get(), MPD_TAG_DATE, 0);
if (tag == nullptr) { return string{tag != nullptr ? tag : ""};
return "";
}
return string{tag};
} }
string mpdsong::get_title() { string mpdsong::get_title() {
assert(m_song); assert(m_song);
auto tag = mpd_song_get_tag(m_song.get(), MPD_TAG_TITLE, 0); auto tag = mpd_song_get_tag(m_song.get(), MPD_TAG_TITLE, 0);
if (tag == nullptr) { return string{tag != nullptr ? tag : ""};
return "";
}
return string{tag};
} }
unsigned mpdsong::get_duration() { unsigned mpdsong::get_duration() {
@ -104,7 +103,18 @@ namespace mpd {
mpdconnection::mpdconnection( mpdconnection::mpdconnection(
const logger& logger, string host, unsigned int port, string password, unsigned int timeout) const logger& logger, string host, unsigned int port, string password, unsigned int timeout)
: m_log(logger), m_host(move(host)), m_port(port), m_password(move(password)), m_timeout(timeout) {} : m_log(logger), m_host(move(host)), m_port(port), m_password(move(password)), m_timeout(timeout) {
memset(&m_signal_action, 0, sizeof(m_signal_action));
m_signal_action.sa_handler = &g_mpd_signal_handler;
if (sigaction(SIGPIPE, &m_signal_action, nullptr) == -1) {
throw mpd_exception("Could not setup signal handler: "s + std::strerror(errno));
}
}
mpdconnection::~mpdconnection() {
m_signal_action.sa_handler = SIG_DFL;
sigaction(SIGPIPE, &m_signal_action, nullptr);
}
void mpdconnection::connect() { void mpdconnection::connect() {
try { try {
@ -134,10 +144,7 @@ namespace mpd {
} }
bool mpdconnection::connected() { bool mpdconnection::connected() {
if (!m_connection) { return m_connection && m_connection != nullptr;
return false;
}
return m_connection != nullptr;
} }
bool mpdconnection::retry_connection(int interval) { bool mpdconnection::retry_connection(int interval) {
@ -150,9 +157,8 @@ namespace mpd {
connect(); connect();
return true; return true;
} catch (const mpd_exception& e) { } catch (const mpd_exception& e) {
std::this_thread::sleep_for(chrono::duration<double>(interval));
} }
std::this_thread::sleep_for(chrono::duration<double>(interval));
} }
return false; return false;
@ -164,12 +170,11 @@ namespace mpd {
void mpdconnection::idle() { void mpdconnection::idle() {
check_connection(m_connection.get()); check_connection(m_connection.get());
if (m_idle) { if (!m_idle) {
return; mpd_send_idle(m_connection.get());
check_errors(m_connection.get());
m_idle = true;
} }
mpd_send_idle(m_connection.get());
check_errors(m_connection.get());
m_idle = true;
} }
int mpdconnection::noidle() { int mpdconnection::noidle() {
@ -188,8 +193,6 @@ namespace mpd {
check_prerequisites(); check_prerequisites();
auto status = make_unique<mpdstatus>(this); auto status = make_unique<mpdstatus>(this);
check_errors(m_connection.get()); check_errors(m_connection.get());
// if (update)
// status->update(-1, this);
return status; return status;
} }
@ -440,7 +443,7 @@ namespace mpd {
return 0; return 0;
} }
math_util::cap<int>(0, 100, percentage); math_util::cap<int>(0, 100, percentage);
return float(m_total_time) * percentage / 100.0f + 0.5f; return math_util::percentage_to_value<double>(percentage, m_total_time);
} }
// }}} // }}}

View file

@ -1,16 +1,15 @@
#include "modules/mpd.hpp" #include <csignal>
#include "drawtypes/iconset.hpp" #include "drawtypes/iconset.hpp"
#include "drawtypes/label.hpp" #include "drawtypes/label.hpp"
#include "drawtypes/progressbar.hpp" #include "drawtypes/progressbar.hpp"
#include "modules/mpd.hpp"
#include "utils/factory.hpp" #include "utils/factory.hpp"
#include "modules/meta/base.inl" #include "modules/meta/base.inl"
POLYBAR_NS POLYBAR_NS
using namespace mpd;
namespace modules { namespace modules {
template class module<mpd_module>; template class module<mpd_module>;
@ -104,9 +103,10 @@ namespace modules {
void mpd_module::idle() { void mpd_module::idle() {
if (connected()) { if (connected()) {
m_quick_attempts = 0;
sleep(80ms); sleep(80ms);
} else { } else {
sleep(2s); sleep(m_quick_attempts++ < 5 ? 0.5s : 2s);
} }
} }
@ -144,7 +144,6 @@ namespace modules {
m_mpd->idle(); m_mpd->idle();
int idle_flags = 0; int idle_flags = 0;
if ((idle_flags = m_mpd->noidle()) != 0) { if ((idle_flags = m_mpd->noidle()) != 0) {
m_status->update(idle_flags, m_mpd.get()); m_status->update(idle_flags, m_mpd.get());
return true; return true;
@ -154,7 +153,7 @@ namespace modules {
m_status->update_timer(); m_status->update_timer();
} }
} catch (const mpd_exception& err) { } catch (const mpd_exception& err) {
m_log.err(err.what()); m_log.err("%s: %s", name(), err.what());
m_mpd.reset(); m_mpd.reset();
return def; return def;
} }
@ -211,7 +210,7 @@ namespace modules {
} }
} }
} catch (const mpd_exception& err) { } catch (const mpd_exception& err) {
m_log.err(err.what()); m_log.err("%s: %s", name(), err.what());
m_mpd.reset(); m_mpd.reset();
} }
@ -328,8 +327,7 @@ namespace modules {
int percentage = 0; int percentage = 0;
if (s.empty()) { if (s.empty()) {
return false; return false;
} } else if (s[0] == '+') {
if (s[0] == '+') {
percentage = status->get_elapsed_percentage() + std::atoi(s.substr(1).c_str()); percentage = status->get_elapsed_percentage() + std::atoi(s.substr(1).c_str());
} else if (s[0] == '-') { } else if (s[0] == '-') {
percentage = status->get_elapsed_percentage() - std::atoi(s.substr(1).c_str()); percentage = status->get_elapsed_percentage() - std::atoi(s.substr(1).c_str());