lib/upnp/Action: common UpnpSendAction() wrapper for pupnp and npupnp
Merge a lot of duplicate code.
This commit is contained in:
@@ -2,33 +2,21 @@
|
||||
// Copyright The Music Player Daemon Project
|
||||
|
||||
#include "lib/upnp/ContentDirectoryService.hxx"
|
||||
#include "lib/upnp/Error.hxx"
|
||||
#include "lib/upnp/Action.hxx"
|
||||
#include "Directory.hxx"
|
||||
#include "util/NumberParser.hxx"
|
||||
#include "util/ScopeExit.hxx"
|
||||
#include "config.h"
|
||||
|
||||
#ifdef USING_PUPNP
|
||||
#include "lib/upnp/ixmlwrap.hxx"
|
||||
#include "lib/upnp/Action.hxx"
|
||||
#include "lib/upnp/UniqueIxml.hxx"
|
||||
#endif
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef USING_PUPNP
|
||||
static void
|
||||
ReadResultTag(UPnPDirContent &dirbuf, IXML_Document *response)
|
||||
ReadResultTag(UPnPDirContent &dirbuf, const UpnpActionResponse &response)
|
||||
{
|
||||
const char *p = ixmlwrap::getFirstElementValue(response, "Result");
|
||||
const char *p = response.GetValue("Result");
|
||||
if (p == nullptr)
|
||||
p = "";
|
||||
|
||||
dirbuf.Parse(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void
|
||||
ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
|
||||
@@ -37,71 +25,28 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
|
||||
unsigned &didreadp,
|
||||
unsigned &totalp) const
|
||||
{
|
||||
#ifdef USING_PUPNP
|
||||
// Some devices require an empty SortCriteria, else bad params
|
||||
IXML_Document *request =
|
||||
MakeActionHelper("Browse", m_serviceType.c_str(),
|
||||
"ObjectID", objectId,
|
||||
"BrowseFlag", "BrowseDirectChildren",
|
||||
"Filter", "*",
|
||||
"SortCriteria", "",
|
||||
"StartingIndex",
|
||||
fmt::format_int{offset}.c_str(),
|
||||
"RequestedCount",
|
||||
fmt::format_int{count}.c_str());
|
||||
if (request == nullptr)
|
||||
throw std::runtime_error("UpnpMakeAction() failed");
|
||||
const auto response = UpnpSendAction(hdl, m_actionURL.c_str(),
|
||||
"Browse", m_serviceType.c_str(),
|
||||
{
|
||||
{"ObjectID", objectId},
|
||||
{"BrowseFlag", "BrowseDirectChildren"},
|
||||
{"Filter", "*"},
|
||||
{"SortCriteria", ""},
|
||||
{"StartingIndex", fmt::format_int{offset}.c_str()},
|
||||
{"RequestedCount", fmt::format_int{count}.c_str()},
|
||||
});
|
||||
|
||||
AtScopeExit(request) { ixmlDocument_free(request); };
|
||||
|
||||
IXML_Document *response;
|
||||
int code = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
|
||||
nullptr /*devUDN*/, request, &response);
|
||||
if (code != UPNP_E_SUCCESS)
|
||||
throw Upnp::MakeError(code, "UpnpSendAction() failed");
|
||||
|
||||
AtScopeExit(response) { ixmlDocument_free(response); };
|
||||
|
||||
const char *value = ixmlwrap::getFirstElementValue(response, "NumberReturned");
|
||||
const char *value = response.GetValue("NumberReturned");
|
||||
didreadp = value != nullptr
|
||||
? ParseUnsigned(value)
|
||||
: 0;
|
||||
|
||||
value = ixmlwrap::getFirstElementValue(response, "TotalMatches");
|
||||
value = response.GetValue("TotalMatches");
|
||||
if (value != nullptr)
|
||||
totalp = ParseUnsigned(value);
|
||||
|
||||
ReadResultTag(dirbuf, response);
|
||||
#else
|
||||
std::vector<std::pair<std::string, std::string>> actionParams{
|
||||
{"ObjectID", objectId},
|
||||
{"BrowseFlag", "BrowseDirectChildren"},
|
||||
{"Filter", "*"},
|
||||
{"SortCriteria", ""},
|
||||
{"StartingIndex", fmt::format_int{offset}.c_str()},
|
||||
{"RequestedCount", fmt::format_int{count}.c_str()},
|
||||
};
|
||||
std::vector<std::pair<std::string, std::string>> responseData;
|
||||
int errcode;
|
||||
std::string errdesc;
|
||||
int code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
|
||||
actionParams, responseData, &errcode, errdesc);
|
||||
if (code != UPNP_E_SUCCESS)
|
||||
throw Upnp::MakeError(code, "UpnpSendAction() failed");
|
||||
|
||||
const char *p = "";
|
||||
didreadp = 0;
|
||||
for (const auto &entry : responseData) {
|
||||
if (entry.first == "Result") {
|
||||
p = entry.second.c_str();
|
||||
} else if (entry.first == "TotalMatches") {
|
||||
totalp = ParseUnsigned(entry.second.c_str());
|
||||
} else if (entry.first == "NumberReturned") {
|
||||
didreadp = ParseUnsigned(entry.second.c_str());
|
||||
}
|
||||
}
|
||||
dirbuf.Parse(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
UPnPDirContent
|
||||
@@ -130,73 +75,29 @@ ContentDirectoryService::search(UpnpClient_Handle hdl,
|
||||
unsigned offset = 0, total = -1, count;
|
||||
|
||||
do {
|
||||
#ifdef USING_PUPNP
|
||||
UniqueIxmlDocument request(MakeActionHelper("Search", m_serviceType.c_str(),
|
||||
"ContainerID", objectId,
|
||||
"SearchCriteria", ss,
|
||||
"Filter", "*",
|
||||
"SortCriteria", "",
|
||||
"StartingIndex",
|
||||
fmt::format_int{offset}.c_str(),
|
||||
"RequestedCount", "0")); // Setting a value here gets twonky into fits
|
||||
if (!request)
|
||||
throw std::runtime_error("UpnpMakeAction() failed");
|
||||
const auto response = UpnpSendAction(hdl, m_actionURL.c_str(),
|
||||
"Search", m_serviceType.c_str(),
|
||||
{
|
||||
{"ContainerID", objectId},
|
||||
{"SearchCriteria", ss},
|
||||
{"Filter", "*"},
|
||||
{"SortCriteria", ""},
|
||||
{"StartingIndex", fmt::format_int{offset}.c_str()},
|
||||
{"RequestedCount", "0"}, // Setting a value here gets twonky into fits
|
||||
});
|
||||
|
||||
IXML_Document *_response;
|
||||
auto code = UpnpSendAction(hdl, m_actionURL.c_str(),
|
||||
m_serviceType.c_str(),
|
||||
nullptr /*devUDN*/,
|
||||
request.get(), &_response);
|
||||
if (code != UPNP_E_SUCCESS)
|
||||
throw Upnp::MakeError(code, "UpnpSendAction() failed");
|
||||
|
||||
UniqueIxmlDocument response(_response);
|
||||
|
||||
const char *value =
|
||||
ixmlwrap::getFirstElementValue(response.get(),
|
||||
"NumberReturned");
|
||||
const char *value = response.GetValue("NumberReturned");
|
||||
count = value != nullptr
|
||||
? ParseUnsigned(value)
|
||||
: 0;
|
||||
|
||||
offset += count;
|
||||
|
||||
value = ixmlwrap::getFirstElementValue(response.get(),
|
||||
"TotalMatches");
|
||||
value = response.GetValue("TotalMatches");
|
||||
if (value != nullptr)
|
||||
total = ParseUnsigned(value);
|
||||
|
||||
ReadResultTag(dirbuf, response.get());
|
||||
#else
|
||||
std::vector<std::pair<std::string, std::string>> actionParams{
|
||||
{"ContainerID", objectId},
|
||||
{"SearchCriteria", ss},
|
||||
{"Filter", "*"},
|
||||
{"SortCriteria", ""},
|
||||
{"StartingIndex", fmt::format_int{offset}.c_str()},
|
||||
{"RequestedCount", "0"}};
|
||||
std::vector<std::pair<std::string, std::string>> responseData;
|
||||
int errcode;
|
||||
std::string errdesc;
|
||||
int code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Search",
|
||||
actionParams, responseData, &errcode, errdesc);
|
||||
if (code != UPNP_E_SUCCESS)
|
||||
throw Upnp::MakeError(code, "UpnpSendAction() failed");
|
||||
|
||||
const char *p = "";
|
||||
count = 0;
|
||||
for (const auto &entry : responseData) {
|
||||
if (entry.first == "Result") {
|
||||
p = entry.second.c_str();
|
||||
} else if (entry.first == "TotalMatches") {
|
||||
total = ParseUnsigned(entry.second.c_str());
|
||||
} else if (entry.first == "NumberReturned") {
|
||||
count = ParseUnsigned(entry.second.c_str());
|
||||
offset += count;
|
||||
}
|
||||
}
|
||||
dirbuf.Parse(p);
|
||||
#endif
|
||||
ReadResultTag(dirbuf, response);
|
||||
} while (count > 0 && offset < total);
|
||||
|
||||
return dirbuf;
|
||||
@@ -206,46 +107,18 @@ UPnPDirContent
|
||||
ContentDirectoryService::getMetadata(UpnpClient_Handle hdl,
|
||||
const char *objectId) const
|
||||
{
|
||||
#ifdef USING_PUPNP
|
||||
// Create request
|
||||
UniqueIxmlDocument request(MakeActionHelper("Browse", m_serviceType.c_str(),
|
||||
"ObjectID", objectId,
|
||||
"BrowseFlag", "BrowseMetadata",
|
||||
"Filter", "*",
|
||||
"SortCriteria", "",
|
||||
"StartingIndex", "0",
|
||||
"RequestedCount", "1"));
|
||||
if (request == nullptr)
|
||||
throw std::runtime_error("UpnpMakeAction() failed");
|
||||
const auto response = UpnpSendAction(hdl, m_actionURL.c_str(),
|
||||
"Browse", m_serviceType.c_str(),
|
||||
{
|
||||
{"ObjectID", objectId},
|
||||
{"BrowseFlag", "BrowseMetadata"},
|
||||
{"Filter", "*"},
|
||||
{"SortCriteria", ""},
|
||||
{"StartingIndex", "0"},
|
||||
{"RequestedCount", "1"},
|
||||
});
|
||||
|
||||
IXML_Document *_response;
|
||||
auto code = UpnpSendAction(hdl, m_actionURL.c_str(),
|
||||
m_serviceType.c_str(),
|
||||
nullptr /*devUDN*/, request.get(), &_response);
|
||||
if (code != UPNP_E_SUCCESS)
|
||||
throw Upnp::MakeError(code, "UpnpSendAction() failed");
|
||||
|
||||
UniqueIxmlDocument response(_response);
|
||||
UPnPDirContent dirbuf;
|
||||
ReadResultTag(dirbuf, response.get());
|
||||
ReadResultTag(dirbuf, response);
|
||||
return dirbuf;
|
||||
#else
|
||||
std::vector<std::pair<std::string, std::string>> actionParams{
|
||||
{"ObjectID", objectId}, {"BrowseFlag", "BrowseMetadata"},
|
||||
{"Filter", "*"}, {"SortCriteria", ""},
|
||||
{"StartingIndex", "0"}, {"RequestedCount", "1"}};
|
||||
std::vector<std::pair<std::string, std::string>> responseData;
|
||||
int errcode;
|
||||
std::string errdesc;
|
||||
int code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
|
||||
actionParams, responseData, &errcode, errdesc);
|
||||
if (code != UPNP_E_SUCCESS)
|
||||
throw Upnp::MakeError(code, "UpnpSendAction() failed");
|
||||
|
||||
auto it = std::find_if(responseData.begin(), responseData.end(), [](auto&& entry){ return entry.first == "Result"; });
|
||||
const char *p = it != responseData.end() ? it->second.c_str() : "";
|
||||
UPnPDirContent dirbuf;
|
||||
dirbuf.Parse(p);
|
||||
return dirbuf;
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user