mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-29 01:20:14 +00:00
Fixed URL signature and the ability to create new sessions. Also added
the ability to store, load and clear sessions.
This commit is contained in:
parent
e4a92dae4d
commit
1e2582fb1d
@ -44,6 +44,8 @@ namespace musik { namespace core { namespace io {
|
||||
template <typename T>
|
||||
class HttpClient {
|
||||
public:
|
||||
enum class Thread { Current, Background };
|
||||
|
||||
using HttpHeaders = std::unordered_map<std::string, std::string>;
|
||||
using Callback = std::function<void(HttpClient<T>* caller, int, CURLcode)>;
|
||||
using DecoratorCallback = std::function<void(CURL*)>;
|
||||
@ -61,6 +63,7 @@ namespace musik { namespace core { namespace io {
|
||||
HttpClient<T>& Headers(HeaderCallback headersCb);
|
||||
HttpClient<T>& Decorator(DecoratorCallback decoratorCb);
|
||||
HttpClient<T>& Canceled(CanceledCallback canceledCb);
|
||||
HttpClient<T>& Mode(Thread mode);
|
||||
|
||||
const T& Stream() const { return this->ostream; }
|
||||
const HttpHeaders& ResponseHeaders() const { return this->responseHeaders; }
|
||||
@ -79,6 +82,8 @@ namespace musik { namespace core { namespace io {
|
||||
static size_t CurlHeaderCallback(char *buffer, size_t size, size_t nitems, void *userdata);
|
||||
static std::string DefaultUserAgent();
|
||||
|
||||
void RunOnCurrentThread(Callback callback);
|
||||
|
||||
std::recursive_mutex mutex;
|
||||
std::shared_ptr<std::thread> thread;
|
||||
|
||||
@ -89,6 +94,7 @@ namespace musik { namespace core { namespace io {
|
||||
DecoratorCallback decoratorCb;
|
||||
CanceledCallback canceledCallback;
|
||||
bool cancel;
|
||||
Thread mode{ Thread::Background };
|
||||
CURL* curl;
|
||||
};
|
||||
|
||||
@ -219,26 +225,36 @@ namespace musik { namespace core { namespace io {
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
|
||||
}
|
||||
|
||||
this->thread.reset(new std::thread([callback, this] {
|
||||
if (this->cancel) {
|
||||
if (this->canceledCallback) {
|
||||
this->canceledCallback(this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
CURLcode curlCode = curl_easy_perform(this->curl);
|
||||
int httpStatus = 0;
|
||||
curl_easy_getinfo(this->curl, CURLINFO_RESPONSE_CODE, &httpStatus);
|
||||
|
||||
if (callback) {
|
||||
callback(this, httpStatus, curlCode);
|
||||
}
|
||||
}
|
||||
}));
|
||||
if (mode == Thread::Background) {
|
||||
this->thread.reset(new std::thread([callback, this] {
|
||||
this->RunOnCurrentThread(callback);
|
||||
}));
|
||||
}
|
||||
else {
|
||||
this->RunOnCurrentThread(callback);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void HttpClient<T>::RunOnCurrentThread(Callback callback) {
|
||||
CURLcode curlCode = curl_easy_perform(this->curl);
|
||||
|
||||
if (this->cancel) {
|
||||
if (this->canceledCallback) {
|
||||
this->canceledCallback(this);
|
||||
}
|
||||
}
|
||||
|
||||
int httpStatus = 0;
|
||||
curl_easy_getinfo(this->curl, CURLINFO_RESPONSE_CODE, &httpStatus);
|
||||
|
||||
if (callback) {
|
||||
callback(this, httpStatus, curlCode);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void HttpClient<T>::Wait() {
|
||||
std::unique_lock<std::recursive_mutex> lock(this->mutex);
|
||||
@ -254,6 +270,12 @@ namespace musik { namespace core { namespace io {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
HttpClient<T>& HttpClient<T>::Mode(Thread mode) {
|
||||
this->mode = mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
HttpClient<T>& HttpClient<T>::Header(const std::string& key, const std::string& value) {
|
||||
this->requestHeaders[key] = value;
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#ifdef WIN32
|
||||
/* nothing special for Win32 */
|
||||
#include <shellapi.h>
|
||||
#elif __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#else
|
||||
@ -57,69 +57,7 @@
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
std::string musik::core::GetPluginDirectory() {
|
||||
std::string path(GetApplicationDirectory());
|
||||
path.append("/plugins/");
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string musik::core::GetApplicationDirectory() {
|
||||
std::string result;
|
||||
|
||||
#ifdef WIN32
|
||||
wchar_t widePath[2048];
|
||||
int length = GetModuleFileName(NULL, widePath, 2048);
|
||||
if (length != 0 && length < 2048) {
|
||||
result.assign(GetPath(u16to8(widePath).c_str()));
|
||||
}
|
||||
#elif __APPLE__
|
||||
char pathbuf[PATH_MAX + 1];
|
||||
uint32_t bufsize = sizeof(pathbuf);
|
||||
_NSGetExecutablePath(pathbuf, &bufsize);
|
||||
result.assign(pathbuf);
|
||||
size_t last = result.find_last_of("/");
|
||||
result = result.substr(0, last); /* remove filename component */
|
||||
#else
|
||||
char pathbuf[PATH_MAX + 1] = { 0 };
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
int mib[4];
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PATHNAME;
|
||||
mib[3] = -1;
|
||||
size_t bufsize = sizeof(pathbuf);
|
||||
sysctl(mib, 4, pathbuf, &bufsize, nullptr, 0);
|
||||
#else
|
||||
std::string pathToProc = boost::str(boost::format("/proc/%d/exe") % (int) getpid());
|
||||
readlink(pathToProc.c_str(), pathbuf, PATH_MAX);
|
||||
#endif
|
||||
|
||||
result.assign(pathbuf);
|
||||
size_t last = result.find_last_of("/");
|
||||
result = result.substr(0, last); /* remove filename component */
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string musik::core::GetHomeDirectory() {
|
||||
std::string directory;
|
||||
|
||||
#ifdef WIN32
|
||||
DWORD bufferSize = GetEnvironmentVariable(L"USERPROFILE", 0, 0);
|
||||
wchar_t *buffer = new wchar_t[bufferSize + 2];
|
||||
GetEnvironmentVariable(L"USERPROFILE", buffer, bufferSize);
|
||||
directory.assign(u16to8(buffer));
|
||||
delete[] buffer;
|
||||
#else
|
||||
directory = std::string(std::getenv("HOME"));
|
||||
#endif
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
static std::string GetDataDirectoryRoot() {
|
||||
static std::string getDataDirectoryRoot() {
|
||||
std::string directory;
|
||||
|
||||
#ifdef WIN32
|
||||
@ -135,163 +73,241 @@ static std::string GetDataDirectoryRoot() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
std::string musik::core::GetDataDirectory(bool create) {
|
||||
std::string directory =
|
||||
|
||||
#ifdef WIN32
|
||||
GetDataDirectoryRoot() + std::string("/musikcube/");
|
||||
#else
|
||||
GetDataDirectoryRoot() + std::string("/.musikcube/");
|
||||
#endif
|
||||
|
||||
if (create) {
|
||||
boost::filesystem::path path(directory);
|
||||
if (!boost::filesystem::exists(path)) {
|
||||
boost::filesystem::create_directories(path);
|
||||
}
|
||||
}
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
inline void silentDelete(const std::string fn) {
|
||||
static inline void silentDelete(const std::string fn) {
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::remove(boost::filesystem::path(fn), ec);
|
||||
}
|
||||
|
||||
void musik::core::RemoveOldDlls() {
|
||||
#ifdef WIN32
|
||||
std::string path = GetPluginDirectory();
|
||||
silentDelete(path + "libcurl.dll");
|
||||
silentDelete(path + "crypto-41.dll");
|
||||
silentDelete(path + "ssl-43.dll");
|
||||
silentDelete(path + "tls-15.dll");
|
||||
#endif
|
||||
}
|
||||
namespace musik { namespace core {
|
||||
|
||||
void musik::core::MigrateOldDataDirectory() {
|
||||
std::string oldDirectory =
|
||||
|
||||
#ifdef WIN32
|
||||
GetDataDirectoryRoot() + std::string("/mC2/");
|
||||
#else
|
||||
GetDataDirectoryRoot() + std::string("/.mC2/");
|
||||
#endif
|
||||
|
||||
std::string newDirectory = GetDataDirectory(false);
|
||||
|
||||
boost::filesystem::path oldPath(oldDirectory);
|
||||
boost::filesystem::path newPath(newDirectory);
|
||||
|
||||
if (boost::filesystem::exists(oldPath) &&
|
||||
!boost::filesystem::exists(newPath))
|
||||
{
|
||||
boost::filesystem::rename(oldPath, newPath);
|
||||
}
|
||||
}
|
||||
|
||||
std::string musik::core::GetPath(const std::string &sFile) {
|
||||
std::string sPath;
|
||||
int length;
|
||||
|
||||
#ifdef WIN32
|
||||
wchar_t widePath[2048];
|
||||
wchar_t *szFile = NULL;
|
||||
|
||||
length = GetFullPathName(u8to16(sFile).c_str(), 2048, widePath, &szFile);
|
||||
if(length != 0 && length < 2048) {
|
||||
sPath.assign(u16to8(widePath).c_str());
|
||||
if(szFile!=0) {
|
||||
std::string sTheFile = u16to8(szFile);
|
||||
sPath.assign(sPath.substr(0,length-sTheFile.length()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
sPath.assign(sFile);
|
||||
}
|
||||
#else
|
||||
char* szDir;
|
||||
sPath.assign(getcwd((char*)szDir, (size_t) length));
|
||||
#endif
|
||||
|
||||
return sPath;
|
||||
}
|
||||
|
||||
int64_t musik::core::Checksum(char *data,unsigned int bytes) {
|
||||
int64_t sum = 0;
|
||||
for(unsigned int i = 0; i < bytes; ++i) {
|
||||
char ch = *(data + i);
|
||||
sum += (int64_t) ch;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
size_t musik::core::CopyString(const std::string& src, char* dst, size_t size) {
|
||||
size_t len = src.size() + 1; /* space for the null terminator */
|
||||
if (dst) {
|
||||
size_t copied = src.copy(dst, size - 1);
|
||||
dst[copied] = '\0';
|
||||
return copied + 1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
bool musik::core::FileToByteArray(const std::string& path, char** target, int& size, bool nullTerminate) {
|
||||
#ifdef WIN32
|
||||
std::wstring u16fn = u8to16(path);
|
||||
FILE* file = _wfopen(u16fn.c_str(), L"rb");
|
||||
#else
|
||||
FILE* file = fopen(path.c_str(), "rb");
|
||||
#endif
|
||||
|
||||
*target = nullptr;
|
||||
size = 0;
|
||||
|
||||
if (!file) {
|
||||
return false;
|
||||
std::string GetPluginDirectory() {
|
||||
std::string path(GetApplicationDirectory());
|
||||
path.append("/plugins/");
|
||||
return path;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
std::string GetApplicationDirectory() {
|
||||
std::string result;
|
||||
|
||||
if (fseek(file, 0L, SEEK_END) == 0) {
|
||||
long fileSize = ftell(file);
|
||||
if (fileSize == -1) {
|
||||
goto close_and_return;
|
||||
#ifdef WIN32
|
||||
wchar_t widePath[2048];
|
||||
int length = GetModuleFileName(NULL, widePath, 2048);
|
||||
if (length != 0 && length < 2048) {
|
||||
result.assign(GetPath(u16to8(widePath).c_str()));
|
||||
}
|
||||
#elif __APPLE__
|
||||
char pathbuf[PATH_MAX + 1];
|
||||
uint32_t bufsize = sizeof(pathbuf);
|
||||
_NSGetExecutablePath(pathbuf, &bufsize);
|
||||
result.assign(pathbuf);
|
||||
size_t last = result.find_last_of("/");
|
||||
result = result.substr(0, last); /* remove filename component */
|
||||
#else
|
||||
char pathbuf[PATH_MAX + 1] = { 0 };
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
int mib[4];
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PATHNAME;
|
||||
mib[3] = -1;
|
||||
size_t bufsize = sizeof(pathbuf);
|
||||
sysctl(mib, 4, pathbuf, &bufsize, nullptr, 0);
|
||||
#else
|
||||
std::string pathToProc = boost::str(boost::format("/proc/%d/exe") % (int) getpid());
|
||||
readlink(pathToProc.c_str(), pathbuf, PATH_MAX);
|
||||
#endif
|
||||
|
||||
result.assign(pathbuf);
|
||||
size_t last = result.find_last_of("/");
|
||||
result = result.substr(0, last); /* remove filename component */
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetHomeDirectory() {
|
||||
std::string directory;
|
||||
|
||||
#ifdef WIN32
|
||||
DWORD bufferSize = GetEnvironmentVariable(L"USERPROFILE", 0, 0);
|
||||
wchar_t *buffer = new wchar_t[bufferSize + 2];
|
||||
GetEnvironmentVariable(L"USERPROFILE", buffer, bufferSize);
|
||||
directory.assign(u16to8(buffer));
|
||||
delete[] buffer;
|
||||
#else
|
||||
directory = std::string(std::getenv("HOME"));
|
||||
#endif
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
std::string GetDataDirectory(bool create) {
|
||||
std::string directory =
|
||||
|
||||
#ifdef WIN32
|
||||
getDataDirectoryRoot() + std::string("/musikcube/");
|
||||
#else
|
||||
getDataDirectoryRoot() + std::string("/.musikcube/");
|
||||
#endif
|
||||
|
||||
if (create) {
|
||||
boost::filesystem::path path(directory);
|
||||
if (!boost::filesystem::exists(path)) {
|
||||
boost::filesystem::create_directories(path);
|
||||
}
|
||||
}
|
||||
|
||||
if (fseek(file, 0L, SEEK_SET) != 0) {
|
||||
goto close_and_return;
|
||||
return directory;
|
||||
}
|
||||
|
||||
void RemoveOldDlls() {
|
||||
#ifdef WIN32
|
||||
std::string path = GetPluginDirectory();
|
||||
silentDelete(path + "libcurl.dll");
|
||||
silentDelete(path + "crypto-41.dll");
|
||||
silentDelete(path + "ssl-43.dll");
|
||||
silentDelete(path + "tls-15.dll");
|
||||
#endif
|
||||
}
|
||||
|
||||
void MigrateOldDataDirectory() {
|
||||
std::string oldDirectory =
|
||||
|
||||
#ifdef WIN32
|
||||
getDataDirectoryRoot() + std::string("/mC2/");
|
||||
#else
|
||||
getDataDirectoryRoot() + std::string("/.mC2/");
|
||||
#endif
|
||||
|
||||
std::string newDirectory = GetDataDirectory(false);
|
||||
|
||||
boost::filesystem::path oldPath(oldDirectory);
|
||||
boost::filesystem::path newPath(newDirectory);
|
||||
|
||||
if (boost::filesystem::exists(oldPath) &&
|
||||
!boost::filesystem::exists(newPath))
|
||||
{
|
||||
boost::filesystem::rename(oldPath, newPath);
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetPath(const std::string &sFile) {
|
||||
std::string sPath;
|
||||
int length;
|
||||
|
||||
#ifdef WIN32
|
||||
wchar_t widePath[2048];
|
||||
wchar_t *szFile = NULL;
|
||||
|
||||
length = GetFullPathName(u8to16(sFile).c_str(), 2048, widePath, &szFile);
|
||||
if(length != 0 && length < 2048) {
|
||||
sPath.assign(u16to8(widePath).c_str());
|
||||
if(szFile!=0) {
|
||||
std::string sTheFile = u16to8(szFile);
|
||||
sPath.assign(sPath.substr(0,length-sTheFile.length()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
sPath.assign(sFile);
|
||||
}
|
||||
#else
|
||||
char* szDir;
|
||||
sPath.assign(getcwd((char*)szDir, (size_t) length));
|
||||
#endif
|
||||
|
||||
return sPath;
|
||||
}
|
||||
|
||||
int64_t Checksum(char *data,unsigned int bytes) {
|
||||
int64_t sum = 0;
|
||||
for(unsigned int i = 0; i < bytes; ++i) {
|
||||
char ch = *(data + i);
|
||||
sum += (int64_t) ch;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
size_t CopyString(const std::string& src, char* dst, size_t size) {
|
||||
size_t len = src.size() + 1; /* space for the null terminator */
|
||||
if (dst) {
|
||||
size_t copied = src.copy(dst, size - 1);
|
||||
dst[copied] = '\0';
|
||||
return copied + 1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
bool FileToByteArray(const std::string& path, char** target, int& size, bool nullTerminate) {
|
||||
#ifdef WIN32
|
||||
std::wstring u16fn = u8to16(path);
|
||||
FILE* file = _wfopen(u16fn.c_str(), L"rb");
|
||||
#else
|
||||
FILE* file = fopen(path.c_str(), "rb");
|
||||
#endif
|
||||
|
||||
*target = nullptr;
|
||||
size = 0;
|
||||
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*target = (char*)malloc(sizeof(char) * (fileSize + (nullTerminate ? 1 : 0)));
|
||||
size = fread(*target, sizeof(char), fileSize, file);
|
||||
bool success = false;
|
||||
|
||||
if (size == fileSize) {
|
||||
if (nullTerminate) {
|
||||
(*target)[size] = 0;
|
||||
if (fseek(file, 0L, SEEK_END) == 0) {
|
||||
long fileSize = ftell(file);
|
||||
if (fileSize == -1) {
|
||||
goto close_and_return;
|
||||
}
|
||||
|
||||
success = true;
|
||||
if (fseek(file, 0L, SEEK_SET) != 0) {
|
||||
goto close_and_return;
|
||||
}
|
||||
|
||||
*target = (char*)malloc(sizeof(char) * (fileSize + (nullTerminate ? 1 : 0)));
|
||||
size = fread(*target, sizeof(char), fileSize, file);
|
||||
|
||||
if (size == fileSize) {
|
||||
if (nullTerminate) {
|
||||
(*target)[size] = 0;
|
||||
}
|
||||
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
close_and_return:
|
||||
fclose(file);
|
||||
|
||||
if (!success) {
|
||||
free(*target);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
close_and_return:
|
||||
fclose(file);
|
||||
std::string NormalizeDir(std::string path) {
|
||||
path = boost::filesystem::path(path).make_preferred().string();
|
||||
|
||||
if (!success) {
|
||||
free(*target);
|
||||
std::string sep(1, boost::filesystem::path::preferred_separator);
|
||||
if (path.size() && path.substr(path.size() - 1, 1) != sep) {
|
||||
path += sep;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
std::string musik::core::NormalizeDir(std::string path) {
|
||||
path = boost::filesystem::path(path).make_preferred().string();
|
||||
|
||||
std::string sep(1, boost::filesystem::path::preferred_separator);
|
||||
if (path.size() && path.substr(path.size() - 1, 1) != sep) {
|
||||
path += sep;
|
||||
void OpenFile(const std::string& path) {
|
||||
#ifdef WIN32
|
||||
ShellExecuteA(nullptr, nullptr, path.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
||||
#elif __APPLE__
|
||||
string command = "open " + path;
|
||||
system(command.c_str());
|
||||
#else
|
||||
string command = "xdg-open " + path;
|
||||
system(command.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
} }
|
||||
|
@ -39,18 +39,19 @@
|
||||
|
||||
namespace musik { namespace core {
|
||||
|
||||
std::string GetHomeDirectory();
|
||||
std::string GetApplicationDirectory();
|
||||
std::string GetDataDirectory(bool create = true);
|
||||
std::string GetPath(const std::string &sFile);
|
||||
std::string GetPluginDirectory();
|
||||
std::string NormalizeDir(std::string path);
|
||||
int64_t Checksum(char *data,unsigned int bytes);
|
||||
size_t CopyString(const std::string& src, char* dst, size_t size);
|
||||
bool FileToByteArray(const std::string& path, char** target, int& size, bool nullTerminate = false);
|
||||
extern std::string GetHomeDirectory();
|
||||
extern std::string GetApplicationDirectory();
|
||||
extern std::string GetDataDirectory(bool create = true);
|
||||
extern std::string GetPath(const std::string &sFile);
|
||||
extern std::string GetPluginDirectory();
|
||||
extern std::string NormalizeDir(std::string path);
|
||||
extern void OpenFile(const std::string& path);
|
||||
extern int64_t Checksum(char *data,unsigned int bytes);
|
||||
extern size_t CopyString(const std::string& src, char* dst, size_t size);
|
||||
extern bool FileToByteArray(const std::string& path, char** target, int& size, bool nullTerminate = false);
|
||||
|
||||
/* renames ~/.mC2 -> ~/.musikcube */
|
||||
void MigrateOldDataDirectory();
|
||||
void RemoveOldDlls();
|
||||
extern void MigrateOldDataDirectory();
|
||||
extern void RemoveOldDlls();
|
||||
|
||||
} }
|
||||
|
@ -38,29 +38,45 @@
|
||||
#include "LastFm.h"
|
||||
#include <curl/curl.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <core/support/Preferences.h>
|
||||
#include <core/io/HttpClient.h>
|
||||
#include <core/support/PreferenceKeys.h>
|
||||
#include <app/util/PreferenceKeys.h>
|
||||
#include <json.hpp>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
/* http://www.last.fm/group/Last.fm+Web+Services/forum/21604/_/522900 -- it's ok to
|
||||
put our key in the code */
|
||||
static const std::string API_KEY = "502c69bd3f9946e8e0beee4fcb28c4cd";
|
||||
static const std::string API_KEY = "8b7b7369cd92bbcc071c5f8a1de1d287";
|
||||
static const std::string API_SECRET = "6dc09da925fe5c115b90320213c53b46";
|
||||
static const std::string URL_BASE = "http://ws.audioscrobbler.com/2.0/";
|
||||
static const std::string GET_TOKEN = "auth.gettoken";
|
||||
static const std::string GET_TOKEN = "auth.getToken";
|
||||
static const std::string GET_SESSION = "auth.getSession";
|
||||
static const std::string ACCOUNT_LINK_URL_BASE = "http://www.last.fm/api/auth/?api_key=" + API_KEY + "&token=";
|
||||
|
||||
using namespace musik;
|
||||
using namespace musik::core::prefs;
|
||||
|
||||
using LastFmClient = musik::core::io::HttpClient<std::stringstream>;
|
||||
using Preferences = musik::core::Preferences;
|
||||
using Prefs = std::shared_ptr<Preferences>;
|
||||
|
||||
static std::unique_ptr<LastFmClient> createClient() {
|
||||
return LastFmClient::Create(std::stringstream());
|
||||
}
|
||||
|
||||
static void validate(musik::cube::lastfm::Session& session) {
|
||||
session.valid =
|
||||
session.sessionId.size() &&
|
||||
session.username.size() &&
|
||||
session.token.size();
|
||||
}
|
||||
|
||||
static std::string generateSignedUrl(
|
||||
const std::string& method,
|
||||
std::map<std::string, std::string>&& params = { })
|
||||
{
|
||||
params["format"] = "json";
|
||||
params["method"] = method;
|
||||
params["api_key"] = API_KEY;
|
||||
|
||||
@ -74,6 +90,8 @@ static std::string generateSignedUrl(
|
||||
first = false;
|
||||
}
|
||||
|
||||
toHash += API_SECRET;
|
||||
|
||||
/* compute the sum */
|
||||
unsigned char rawDigest[MD5_DIGEST_LENGTH];
|
||||
MD5((const unsigned char*)toHash.c_str(), toHash.length(), rawDigest);
|
||||
@ -85,19 +103,24 @@ static std::string generateSignedUrl(
|
||||
}
|
||||
hexDigest[32] = 0;
|
||||
|
||||
url += "&api_sig=" + std::string(hexDigest);
|
||||
url += "&format=json&api_sig=" + std::string(hexDigest);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
static inline Prefs settings() {
|
||||
return Preferences::ForComponent(components::Settings);
|
||||
}
|
||||
|
||||
namespace musik { namespace cube { namespace lastfm {
|
||||
|
||||
const std::string InitiateLink() {
|
||||
const std::string CreateAccountLinkToken() {
|
||||
std::string url = generateSignedUrl(GET_TOKEN);
|
||||
std::string token;
|
||||
|
||||
auto client = createClient();
|
||||
client->Url(url)
|
||||
.Mode(LastFmClient::Thread::Current)
|
||||
.Run([&token](LastFmClient* client, int statusCode, CURLcode curlCode) {
|
||||
if (statusCode == 200) {
|
||||
try {
|
||||
@ -108,10 +131,64 @@ namespace musik { namespace cube { namespace lastfm {
|
||||
/* not much we can do... */
|
||||
}
|
||||
}
|
||||
})
|
||||
.Wait();
|
||||
});
|
||||
|
||||
return token.size() ? (ACCOUNT_LINK_URL_BASE + token) : "";
|
||||
return token;
|
||||
}
|
||||
|
||||
extern Session CreateSession(const std::string& token) {
|
||||
std::string url = generateSignedUrl(GET_SESSION, { { "token", token } });
|
||||
|
||||
Session session;
|
||||
session.token = token;
|
||||
|
||||
auto client = createClient();
|
||||
client->Url(url)
|
||||
.Mode(LastFmClient::Thread::Current)
|
||||
.Run([&session](LastFmClient* client, int statusCode, CURLcode curlCode) {
|
||||
if (statusCode == 200) {
|
||||
try {
|
||||
auto json = nlohmann::json::parse(client->Stream().str());
|
||||
auto subscriber = json["session"];
|
||||
session.username = subscriber.value("name", "");
|
||||
session.sessionId = subscriber.value("key", "");
|
||||
}
|
||||
catch (...) {
|
||||
/* not much we can do... */
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
validate(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
const std::string CreateLinkUrl(const std::string& token) {
|
||||
return ACCOUNT_LINK_URL_BASE + token;
|
||||
}
|
||||
|
||||
Session LoadSession() {
|
||||
namespace keys = cube::prefs::keys;
|
||||
auto prefs = settings();
|
||||
Session session;
|
||||
session.token = prefs->GetString(keys::LastFmToken);
|
||||
session.sessionId = prefs->GetString(keys::LastFmSessionId);
|
||||
session.username = prefs->GetString(keys::LastFmUsername);
|
||||
validate(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
void SaveSession(const Session& session) {
|
||||
namespace keys = cube::prefs::keys;
|
||||
auto prefs = settings();
|
||||
prefs->SetString(keys::LastFmToken.c_str(), session.token.c_str());
|
||||
prefs->SetString(keys::LastFmSessionId.c_str(), session.sessionId.c_str());
|
||||
prefs->SetString(keys::LastFmUsername.c_str(), session.username.c_str());
|
||||
}
|
||||
|
||||
void ClearSession() {
|
||||
Session session;
|
||||
SaveSession(session);
|
||||
}
|
||||
|
||||
} } }
|
@ -37,5 +37,15 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
namespace musik { namespace cube { namespace lastfm {
|
||||
extern const std::string InitiateLink();
|
||||
struct Session {
|
||||
bool valid{ false };
|
||||
std::string username, token, sessionId;
|
||||
};
|
||||
|
||||
extern Session LoadSession();
|
||||
extern void SaveSession(const Session& session);
|
||||
extern const std::string CreateAccountLinkToken();
|
||||
extern const std::string CreateLinkUrl(const std::string& token);
|
||||
extern Session CreateSession(const std::string& token);
|
||||
extern void ClearSession();
|
||||
} } }
|
@ -51,6 +51,9 @@ namespace musik { namespace cube { namespace prefs {
|
||||
const std::string keys::LastBrowseDirectoryRoot = "LastBrowseDirectoryRoot";
|
||||
const std::string keys::LastCategoryFilter = "LastCategoryFilter";
|
||||
const std::string keys::LastTrackFilter = "LastTrackFilter";
|
||||
const std::string keys::LastFmToken = "LastFmToken";
|
||||
const std::string keys::LastFmSessionId = "LastFmSessionId";
|
||||
const std::string keys::LastFmUsername = "LastFmUsername";
|
||||
|
||||
} } }
|
||||
|
||||
|
@ -53,7 +53,9 @@ namespace musik { namespace cube { namespace prefs {
|
||||
extern const std::string LastBrowseDirectoryRoot;
|
||||
extern const std::string LastCategoryFilter;
|
||||
extern const std::string LastTrackFilter;
|
||||
|
||||
extern const std::string LastFmToken;
|
||||
extern const std::string LastFmSessionId;
|
||||
extern const std::string LastFmUsername;
|
||||
}
|
||||
|
||||
} } }
|
||||
|
Loading…
x
Reference in New Issue
Block a user