db/proxy: throw exception on error
This commit is contained in:
@@ -48,6 +48,18 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
class LibmpdclientError final : std::runtime_error {
|
||||||
|
enum mpd_error code;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LibmpdclientError(enum mpd_error _code, const char *_msg)
|
||||||
|
:std::runtime_error(_msg), code(_code) {}
|
||||||
|
|
||||||
|
enum mpd_error GetCode() const {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class ProxySong : public LightSong {
|
class ProxySong : public LightSong {
|
||||||
Tag tag2;
|
Tag tag2;
|
||||||
|
|
||||||
@@ -132,9 +144,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool Configure(const ConfigBlock &block, Error &error);
|
bool Configure(const ConfigBlock &block, Error &error);
|
||||||
|
|
||||||
bool Connect(Error &error);
|
void Connect();
|
||||||
bool CheckConnection(Error &error);
|
void CheckConnection();
|
||||||
bool EnsureConnected(Error &error);
|
void EnsureConnected();
|
||||||
|
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
|
|
||||||
@@ -228,7 +240,7 @@ Convert(TagType tag_type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
MakeError(struct mpd_connection *connection, Error &error)
|
ThrowError(struct mpd_connection *connection)
|
||||||
{
|
{
|
||||||
const auto code = mpd_connection_get_error(connection);
|
const auto code = mpd_connection_get_error(connection);
|
||||||
|
|
||||||
@@ -241,23 +253,20 @@ MakeError(struct mpd_connection *connection, Error &error)
|
|||||||
as our "enum ack" */
|
as our "enum ack" */
|
||||||
const auto server_error =
|
const auto server_error =
|
||||||
mpd_connection_get_server_error(connection);
|
mpd_connection_get_server_error(connection);
|
||||||
error.Set(ack_domain, (int)server_error,
|
throw ProtocolError((enum ack)server_error,
|
||||||
mpd_connection_get_error_message(connection));
|
mpd_connection_get_error_message(connection));
|
||||||
} else {
|
} else {
|
||||||
error.Set(libmpdclient_domain, (int)code,
|
throw LibmpdclientError(code,
|
||||||
mpd_connection_get_error_message(connection));
|
mpd_connection_get_error_message(connection));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
CheckError(struct mpd_connection *connection, Error &error)
|
CheckError(struct mpd_connection *connection)
|
||||||
{
|
{
|
||||||
const auto code = mpd_connection_get_error(connection);
|
const auto code = mpd_connection_get_error(connection);
|
||||||
if (code == MPD_ERROR_SUCCESS)
|
if (code != MPD_ERROR_SUCCESS)
|
||||||
return true;
|
ThrowError(connection);
|
||||||
|
|
||||||
MakeError(connection, error);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@@ -354,10 +363,9 @@ ProxyDatabase::Configure(const ConfigBlock &block, gcc_unused Error &error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ProxyDatabase::Open(Error &error)
|
ProxyDatabase::Open(gcc_unused Error &error)
|
||||||
{
|
{
|
||||||
if (!Connect(error))
|
Connect();
|
||||||
return false;
|
|
||||||
|
|
||||||
update_stamp = 0;
|
update_stamp = 0;
|
||||||
|
|
||||||
@@ -371,22 +379,21 @@ ProxyDatabase::Close()
|
|||||||
Disconnect();
|
Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
ProxyDatabase::Connect(Error &error)
|
ProxyDatabase::Connect()
|
||||||
{
|
{
|
||||||
const char *_host = host.empty() ? nullptr : host.c_str();
|
const char *_host = host.empty() ? nullptr : host.c_str();
|
||||||
connection = mpd_connection_new(_host, port, 0);
|
connection = mpd_connection_new(_host, port, 0);
|
||||||
if (connection == nullptr) {
|
if (connection == nullptr)
|
||||||
error.Set(libmpdclient_domain, (int)MPD_ERROR_OOM,
|
throw LibmpdclientError(MPD_ERROR_OOM, "Out of memory");
|
||||||
"Out of memory");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CheckError(connection, error)) {
|
try {
|
||||||
|
CheckError(connection);
|
||||||
|
} catch (...) {
|
||||||
mpd_connection_free(connection);
|
mpd_connection_free(connection);
|
||||||
connection = nullptr;
|
connection = nullptr;
|
||||||
|
|
||||||
return false;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LIBMPDCLIENT_CHECK_VERSION(2, 10, 0)
|
#if LIBMPDCLIENT_CHECK_VERSION(2, 10, 0)
|
||||||
@@ -398,41 +405,43 @@ ProxyDatabase::Connect(Error &error)
|
|||||||
|
|
||||||
SocketMonitor::Open(mpd_async_get_fd(mpd_connection_get_async(connection)));
|
SocketMonitor::Open(mpd_async_get_fd(mpd_connection_get_async(connection)));
|
||||||
IdleMonitor::Schedule();
|
IdleMonitor::Schedule();
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
ProxyDatabase::CheckConnection(Error &error)
|
ProxyDatabase::CheckConnection()
|
||||||
{
|
{
|
||||||
assert(connection != nullptr);
|
assert(connection != nullptr);
|
||||||
|
|
||||||
if (!mpd_connection_clear_error(connection)) {
|
if (!mpd_connection_clear_error(connection)) {
|
||||||
Disconnect();
|
Disconnect();
|
||||||
return Connect(error);
|
Connect();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_idle) {
|
if (is_idle) {
|
||||||
unsigned idle = mpd_run_noidle(connection);
|
unsigned idle = mpd_run_noidle(connection);
|
||||||
if (idle == 0 && !CheckError(connection, error)) {
|
if (idle == 0) {
|
||||||
Disconnect();
|
try {
|
||||||
return false;
|
CheckError(connection);
|
||||||
|
} catch (...) {
|
||||||
|
Disconnect();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
idle_received |= idle;
|
idle_received |= idle;
|
||||||
is_idle = false;
|
is_idle = false;
|
||||||
IdleMonitor::Schedule();
|
IdleMonitor::Schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
ProxyDatabase::EnsureConnected(Error &error)
|
ProxyDatabase::EnsureConnected()
|
||||||
{
|
{
|
||||||
return connection != nullptr
|
if (connection != nullptr)
|
||||||
? CheckConnection(error)
|
CheckConnection();
|
||||||
: Connect(error);
|
else
|
||||||
|
Connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -460,8 +469,9 @@ ProxyDatabase::OnSocketReady(gcc_unused unsigned flags)
|
|||||||
|
|
||||||
unsigned idle = (unsigned)mpd_recv_idle(connection, false);
|
unsigned idle = (unsigned)mpd_recv_idle(connection, false);
|
||||||
if (idle == 0) {
|
if (idle == 0) {
|
||||||
Error error;
|
try {
|
||||||
if (!CheckError(connection, error)) {
|
CheckError(connection);
|
||||||
|
} catch (const std::runtime_error &error) {
|
||||||
LogError(error);
|
LogError(error);
|
||||||
Disconnect();
|
Disconnect();
|
||||||
return false;
|
return false;
|
||||||
@@ -494,9 +504,11 @@ ProxyDatabase::OnIdle()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!mpd_send_idle_mask(connection, MPD_IDLE_DATABASE)) {
|
if (!mpd_send_idle_mask(connection, MPD_IDLE_DATABASE)) {
|
||||||
Error error;
|
try {
|
||||||
MakeError(connection, error);
|
ThrowError(connection);
|
||||||
LogError(error);
|
} catch (const std::runtime_error &error) {
|
||||||
|
LogError(error);
|
||||||
|
}
|
||||||
|
|
||||||
SocketMonitor::Steal();
|
SocketMonitor::Steal();
|
||||||
mpd_connection_free(connection);
|
mpd_connection_free(connection);
|
||||||
@@ -509,23 +521,19 @@ ProxyDatabase::OnIdle()
|
|||||||
}
|
}
|
||||||
|
|
||||||
const LightSong *
|
const LightSong *
|
||||||
ProxyDatabase::GetSong(const char *uri, Error &error) const
|
ProxyDatabase::GetSong(const char *uri, gcc_unused Error &error) const
|
||||||
{
|
{
|
||||||
// TODO: eliminate the const_cast
|
// TODO: eliminate the const_cast
|
||||||
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
|
const_cast<ProxyDatabase *>(this)->EnsureConnected();
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (!mpd_send_list_meta(connection, uri)) {
|
if (!mpd_send_list_meta(connection, uri))
|
||||||
MakeError(connection, error);
|
ThrowError(connection);
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mpd_song *song = mpd_recv_song(connection);
|
struct mpd_song *song = mpd_recv_song(connection);
|
||||||
if (!mpd_response_finish(connection)) {
|
if (!mpd_response_finish(connection)) {
|
||||||
if (song != nullptr)
|
if (song != nullptr)
|
||||||
mpd_song_free(song);
|
mpd_song_free(song);
|
||||||
MakeError(connection, error);
|
ThrowError(connection);
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (song == nullptr)
|
if (song == nullptr)
|
||||||
@@ -653,14 +661,11 @@ Visit(struct mpd_connection *connection, const char *uri,
|
|||||||
VisitDirectory visit_directory, VisitSong visit_song,
|
VisitDirectory visit_directory, VisitSong visit_song,
|
||||||
VisitPlaylist visit_playlist, Error &error)
|
VisitPlaylist visit_playlist, Error &error)
|
||||||
{
|
{
|
||||||
if (!mpd_send_list_meta(connection, uri)) {
|
if (!mpd_send_list_meta(connection, uri))
|
||||||
MakeError(connection, error);
|
ThrowError(connection);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<ProxyEntity> entities(ReceiveEntities(connection));
|
std::list<ProxyEntity> entities(ReceiveEntities(connection));
|
||||||
if (!CheckError(connection, error))
|
CheckError(connection);
|
||||||
return false;
|
|
||||||
|
|
||||||
for (const auto &entity : entities) {
|
for (const auto &entity : entities) {
|
||||||
switch (mpd_entity_get_type(entity)) {
|
switch (mpd_entity_get_type(entity)) {
|
||||||
@@ -707,10 +712,8 @@ SearchSongs(struct mpd_connection *connection,
|
|||||||
|
|
||||||
if (!mpd_search_db_songs(connection, exact) ||
|
if (!mpd_search_db_songs(connection, exact) ||
|
||||||
!SendConstraints(connection, selection) ||
|
!SendConstraints(connection, selection) ||
|
||||||
!mpd_search_commit(connection)) {
|
!mpd_search_commit(connection))
|
||||||
MakeError(connection, error);
|
ThrowError(connection);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
struct mpd_song *song;
|
struct mpd_song *song;
|
||||||
@@ -721,10 +724,8 @@ SearchSongs(struct mpd_connection *connection,
|
|||||||
visit_song(song2, error);
|
visit_song(song2, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mpd_response_finish(connection) && result) {
|
if (!mpd_response_finish(connection) && result)
|
||||||
MakeError(connection, error);
|
ThrowError(connection);
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -754,8 +755,7 @@ ProxyDatabase::Visit(const DatabaseSelection &selection,
|
|||||||
Error &error) const
|
Error &error) const
|
||||||
{
|
{
|
||||||
// TODO: eliminate the const_cast
|
// TODO: eliminate the const_cast
|
||||||
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
|
const_cast<ProxyDatabase *>(this)->EnsureConnected();
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!visit_directory && !visit_playlist && selection.recursive &&
|
if (!visit_directory && !visit_playlist && selection.recursive &&
|
||||||
(ServerSupportsSearchBase(connection)
|
(ServerSupportsSearchBase(connection)
|
||||||
@@ -780,8 +780,7 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
|
|||||||
Error &error) const
|
Error &error) const
|
||||||
{
|
{
|
||||||
// TODO: eliminate the const_cast
|
// TODO: eliminate the const_cast
|
||||||
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
|
const_cast<ProxyDatabase *>(this)->EnsureConnected();
|
||||||
return false;
|
|
||||||
|
|
||||||
enum mpd_tag_type tag_type2 = Convert(tag_type);
|
enum mpd_tag_type tag_type2 = Convert(tag_type);
|
||||||
if (tag_type2 == MPD_TAG_COUNT) {
|
if (tag_type2 == MPD_TAG_COUNT) {
|
||||||
@@ -790,17 +789,13 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!mpd_search_db_tags(connection, tag_type2) ||
|
if (!mpd_search_db_tags(connection, tag_type2) ||
|
||||||
!SendConstraints(connection, selection)) {
|
!SendConstraints(connection, selection))
|
||||||
MakeError(connection, error);
|
ThrowError(connection);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use group_mask
|
// TODO: use group_mask
|
||||||
|
|
||||||
if (!mpd_search_commit(connection)) {
|
if (!mpd_search_commit(connection))
|
||||||
MakeError(connection, error);
|
ThrowError(connection);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
@@ -825,31 +820,26 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
|
|||||||
result = visit_tag(tag.Commit(), error);
|
result = visit_tag(tag.Commit(), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mpd_response_finish(connection) && result) {
|
if (!mpd_response_finish(connection) && result)
|
||||||
MakeError(connection, error);
|
ThrowError(connection);
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ProxyDatabase::GetStats(const DatabaseSelection &selection,
|
ProxyDatabase::GetStats(const DatabaseSelection &selection,
|
||||||
DatabaseStats &stats, Error &error) const
|
DatabaseStats &stats, gcc_unused Error &error) const
|
||||||
{
|
{
|
||||||
// TODO: match
|
// TODO: match
|
||||||
(void)selection;
|
(void)selection;
|
||||||
|
|
||||||
// TODO: eliminate the const_cast
|
// TODO: eliminate the const_cast
|
||||||
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
|
const_cast<ProxyDatabase *>(this)->EnsureConnected();
|
||||||
return false;
|
|
||||||
|
|
||||||
struct mpd_stats *stats2 =
|
struct mpd_stats *stats2 =
|
||||||
mpd_run_stats(connection);
|
mpd_run_stats(connection);
|
||||||
if (stats2 == nullptr) {
|
if (stats2 == nullptr)
|
||||||
MakeError(connection, error);
|
ThrowError(connection);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
update_stamp = (time_t)mpd_stats_get_db_update_time(stats2);
|
update_stamp = (time_t)mpd_stats_get_db_update_time(stats2);
|
||||||
|
|
||||||
@@ -864,16 +854,15 @@ ProxyDatabase::GetStats(const DatabaseSelection &selection,
|
|||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
ProxyDatabase::Update(const char *uri_utf8, bool discard,
|
ProxyDatabase::Update(const char *uri_utf8, bool discard,
|
||||||
Error &error)
|
gcc_unused Error &error)
|
||||||
{
|
{
|
||||||
if (!EnsureConnected(error))
|
EnsureConnected();
|
||||||
return 0;
|
|
||||||
|
|
||||||
unsigned id = discard
|
unsigned id = discard
|
||||||
? mpd_run_rescan(connection, uri_utf8)
|
? mpd_run_rescan(connection, uri_utf8)
|
||||||
: mpd_run_update(connection, uri_utf8);
|
: mpd_run_update(connection, uri_utf8);
|
||||||
if (id == 0)
|
if (id == 0)
|
||||||
CheckError(connection, error);
|
CheckError(connection);
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user