mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-09-08 21:20:45 +02:00
Import Hatchet plugin
This commit is contained in:
@@ -37,6 +37,7 @@ add_definitions( "-DQT_STRICT_ITERATORS" )
|
|||||||
option(BUILD_GUI "Build Tomahawk with GUI" ON)
|
option(BUILD_GUI "Build Tomahawk with GUI" ON)
|
||||||
option(BUILD_RELEASE "Generate TOMAHAWK_VERSION without GIT info" OFF)
|
option(BUILD_RELEASE "Generate TOMAHAWK_VERSION without GIT info" OFF)
|
||||||
option(BUILD_TESTS "Build Tomahawk with unit tests" ON)
|
option(BUILD_TESTS "Build Tomahawk with unit tests" ON)
|
||||||
|
option(BUILD_HATCHET "Build the Hatchet plugin" OFF)
|
||||||
|
|
||||||
option(WITH_BREAKPAD "Build with breakpad integration" ON)
|
option(WITH_BREAKPAD "Build with breakpad integration" ON)
|
||||||
option(WITH_CRASHREPORTER "Build with CrashReporter" ON)
|
option(WITH_CRASHREPORTER "Build with CrashReporter" ON)
|
||||||
|
@@ -3,16 +3,17 @@ include( ${CMAKE_CURRENT_LIST_DIR}/../../TomahawkAddPlugin.cmake )
|
|||||||
file(GLOB SUBDIRECTORIES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*")
|
file(GLOB SUBDIRECTORIES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*")
|
||||||
foreach(SUBDIRECTORY ${SUBDIRECTORIES})
|
foreach(SUBDIRECTORY ${SUBDIRECTORIES})
|
||||||
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/CMakeLists.txt")
|
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/CMakeLists.txt")
|
||||||
if(SUBDIRECTORY STREQUAL "xmpp")
|
if(SUBDIRECTORY STREQUAL "twitter")
|
||||||
|
elseif(SUBDIRECTORY STREQUAL "xmpp")
|
||||||
if( JREEN_FOUND )
|
if( JREEN_FOUND )
|
||||||
add_subdirectory( xmpp )
|
add_subdirectory( xmpp )
|
||||||
endif()
|
endif()
|
||||||
elseif(SUBDIRECTORY STREQUAL "twitter")
|
elseif(SUBDIRECTORY STREQUAL "hatchet")
|
||||||
if(QTWEETLIB_FOUND AND BUILD_GUI)
|
if(BUILD_HATCHET AND BUILD_GUI)
|
||||||
add_subdirectory( twitter )
|
add_subdirectory(hatchet)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
add_subdirectory( ${SUBDIRECTORY} )
|
add_subdirectory(${SUBDIRECTORY})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
23
src/accounts/hatchet/.gitignore
vendored
Normal file
23
src/accounts/hatchet/.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
*-build/*
|
||||||
|
build/*
|
||||||
|
.directory
|
||||||
|
*.a
|
||||||
|
*.o
|
||||||
|
._*
|
||||||
|
*.user
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
Makefile*
|
||||||
|
moc_*
|
||||||
|
*~
|
||||||
|
*.sublime-project
|
||||||
|
*.sublime-workspace
|
||||||
|
/tomahawk
|
||||||
|
.kdev4
|
||||||
|
*.kdev4
|
||||||
|
*.kate-swp
|
||||||
|
clang/
|
||||||
|
win/
|
||||||
|
gcc/
|
||||||
|
tags
|
||||||
|
.DS_Store
|
52
src/accounts/hatchet/CMakeLists.txt
Normal file
52
src/accounts/hatchet/CMakeLists.txt
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
CMAKE_POLICY(SET CMP0017 NEW)
|
||||||
|
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/Modules")
|
||||||
|
|
||||||
|
if(NOT TOMAHAWK_LIBRARIES)
|
||||||
|
message(STATUS "BUILDING OUTSIDE TOMAHAWK")
|
||||||
|
find_package(Tomahawk REQUIRED)
|
||||||
|
else()
|
||||||
|
message(STATUS "BUILDING INSIDE TOMAHAWK")
|
||||||
|
set(TOMAHAWK_USE_FILE "${CMAKE_SOURCE_DIR}/TomahawkUse.cmake")
|
||||||
|
endif()
|
||||||
|
include( ${TOMAHAWK_USE_FILE} )
|
||||||
|
|
||||||
|
find_package(OpenSSL REQUIRED)
|
||||||
|
find_package(QCA2 REQUIRED)
|
||||||
|
find_package(websocketpp 0.2.99 REQUIRED)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${WEBSOCKETPP_INCLUDE_DIR}
|
||||||
|
${TOMAHAWK_INCLUDE_DIRS}
|
||||||
|
${QCA2_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_definitions(-D_WEBSOCKETPP_CPP11_STL_)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
# http://stackoverflow.com/questions/7226753/osx-lion-xcode-4-1-how-do-i-setup-a-c0x-project/7236451#7236451
|
||||||
|
add_definitions(-std=c++11 -stdlib=libc++ -U__STRICT_ANSI__)
|
||||||
|
set(PLATFORM_SPECIFIC_LINK_LIBRARIES "/usr/lib/libc++.dylib")
|
||||||
|
else()
|
||||||
|
add_definitions(-std=c++0x)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
tomahawk_add_plugin(hatchet
|
||||||
|
TYPE account
|
||||||
|
EXPORT_MACRO ACCOUNTDLLEXPORT_PRO
|
||||||
|
SOURCES
|
||||||
|
account/HatchetAccount.cpp
|
||||||
|
account/HatchetAccountConfig.cpp
|
||||||
|
sip/WebSocket.cpp
|
||||||
|
sip/WebSocketThreadController.cpp
|
||||||
|
sip/HatchetSip.cpp
|
||||||
|
UI
|
||||||
|
account/HatchetAccountConfig.ui
|
||||||
|
LINK_LIBRARIES
|
||||||
|
${TOMAHAWK_LIBRARIES}
|
||||||
|
${QCA2_LIBRARIES}
|
||||||
|
${PLATFORM_SPECIFIC_LINK_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
381
src/accounts/hatchet/account/HatchetAccount.cpp
Normal file
381
src/accounts/hatchet/account/HatchetAccount.cpp
Normal file
@@ -0,0 +1,381 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "HatchetAccount.h"
|
||||||
|
|
||||||
|
#include "HatchetAccountConfig.h"
|
||||||
|
#include "utils/Closure.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "sip/HatchetSip.h"
|
||||||
|
#include "utils/TomahawkUtils.h"
|
||||||
|
|
||||||
|
#include <QtPlugin>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include <qjson/parser.h>
|
||||||
|
#include <qjson/serializer.h>
|
||||||
|
|
||||||
|
using namespace Tomahawk;
|
||||||
|
using namespace Accounts;
|
||||||
|
|
||||||
|
static QPixmap* s_icon = 0;
|
||||||
|
HatchetAccount* HatchetAccount::s_instance = 0;
|
||||||
|
|
||||||
|
#define AUTH_SERVER "http://auth.toma.hk"
|
||||||
|
|
||||||
|
HatchetAccountFactory::HatchetAccountFactory()
|
||||||
|
{
|
||||||
|
#ifndef ENABLE_HEADLESS
|
||||||
|
if ( s_icon == 0 )
|
||||||
|
s_icon = new QPixmap( ":/hatchet-account/hatchet-icon-512x512.png" );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HatchetAccountFactory::~HatchetAccountFactory()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPixmap
|
||||||
|
HatchetAccountFactory::icon() const
|
||||||
|
{
|
||||||
|
return *s_icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Account*
|
||||||
|
HatchetAccountFactory::createAccount( const QString& pluginId )
|
||||||
|
{
|
||||||
|
return new HatchetAccount( pluginId.isEmpty() ? generateId( factoryId() ) : pluginId );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Hatchet account
|
||||||
|
|
||||||
|
HatchetAccount::HatchetAccount( const QString& accountId )
|
||||||
|
: Account( accountId )
|
||||||
|
{
|
||||||
|
s_instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HatchetAccount::~HatchetAccount()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HatchetAccount*
|
||||||
|
HatchetAccount::instance()
|
||||||
|
{
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AccountConfigWidget*
|
||||||
|
HatchetAccount::configurationWidget()
|
||||||
|
{
|
||||||
|
if ( m_configWidget.isNull() )
|
||||||
|
m_configWidget = QWeakPointer<HatchetAccountConfig>( new HatchetAccountConfig( this ) );
|
||||||
|
|
||||||
|
return m_configWidget.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccount::authenticate()
|
||||||
|
{
|
||||||
|
if ( connectionState() == Connected )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( !authToken().isEmpty() )
|
||||||
|
{
|
||||||
|
qDebug() << "Have saved credentials with auth token:" << authToken();
|
||||||
|
if ( sipPlugin() )
|
||||||
|
sipPlugin()->connectPlugin();
|
||||||
|
}
|
||||||
|
else if ( !username().isEmpty() )
|
||||||
|
{
|
||||||
|
// Need to re-prompt for password, since we don't save it!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccount::deauthenticate()
|
||||||
|
{
|
||||||
|
if ( !m_tomahawkSipPlugin.isNull() )
|
||||||
|
sipPlugin()->disconnectPlugin();
|
||||||
|
emit deauthenticated();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccount::setConnectionState( Account::ConnectionState connectionState )
|
||||||
|
{
|
||||||
|
m_state = connectionState;
|
||||||
|
|
||||||
|
emit connectionStateChanged( connectionState );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Account::ConnectionState
|
||||||
|
HatchetAccount::connectionState() const
|
||||||
|
{
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SipPlugin*
|
||||||
|
HatchetAccount::sipPlugin()
|
||||||
|
{
|
||||||
|
if ( m_tomahawkSipPlugin.isNull() )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
m_tomahawkSipPlugin = QWeakPointer< HatchetSipPlugin >( new HatchetSipPlugin( this ) );
|
||||||
|
connect( m_tomahawkSipPlugin.data(), SIGNAL( authUrlDiscovered( Tomahawk::Accounts::HatchetAccount::Service, QString ) ),
|
||||||
|
this, SLOT( authUrlDiscovered( Tomahawk::Accounts::HatchetAccount::Service, QString ) ) );
|
||||||
|
|
||||||
|
return m_tomahawkSipPlugin.data();
|
||||||
|
}
|
||||||
|
return m_tomahawkSipPlugin.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPixmap
|
||||||
|
HatchetAccount::icon() const
|
||||||
|
{
|
||||||
|
return *s_icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
HatchetAccount::isAuthenticated() const
|
||||||
|
{
|
||||||
|
return credentials().contains( "authtoken" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString
|
||||||
|
HatchetAccount::username() const
|
||||||
|
{
|
||||||
|
return credentials().value( "username" ).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QByteArray
|
||||||
|
HatchetAccount::authToken() const
|
||||||
|
{
|
||||||
|
return credentials().value( "authtoken" ).toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccount::doRegister( const QString& username, const QString& password, const QString& email )
|
||||||
|
{
|
||||||
|
if ( username.isEmpty() || password.isEmpty() || email.isEmpty() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap registerCmd;
|
||||||
|
registerCmd[ "command" ] = "register";
|
||||||
|
registerCmd[ "email" ] = email;
|
||||||
|
registerCmd[ "password" ] = password;
|
||||||
|
registerCmd[ "username" ] = username;
|
||||||
|
|
||||||
|
QNetworkReply* reply = buildRequest( "signup", registerCmd );
|
||||||
|
connect( reply, SIGNAL( finished() ), this, SLOT( onRegisterFinished() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccount::loginWithPassword( const QString& username, const QString& password )
|
||||||
|
{
|
||||||
|
if ( username.isEmpty() || password.isEmpty() )
|
||||||
|
{
|
||||||
|
tLog() << "No tomahawk account username or pw, not logging in";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap params;
|
||||||
|
params[ "password" ] = password;
|
||||||
|
params[ "username" ] = username;
|
||||||
|
|
||||||
|
QNetworkReply* reply = buildRequest( "login", params );
|
||||||
|
NewClosure( reply, SIGNAL( finished() ), this, SLOT( onPasswordLoginFinished( QNetworkReply*, const QString& ) ), reply, username );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccount::fetchAccessTokens()
|
||||||
|
{
|
||||||
|
if ( username().isEmpty() || authToken().isEmpty() )
|
||||||
|
{
|
||||||
|
tLog() << "No authToken, not logging in";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap params;
|
||||||
|
params[ "authtoken" ] = authToken();
|
||||||
|
params[ "username" ] = username();
|
||||||
|
|
||||||
|
tLog() << "Fetching access tokens";
|
||||||
|
QNetworkReply* reply = buildRequest( "tokens", params );
|
||||||
|
connect( reply, SIGNAL( finished() ), this, SLOT( onFetchAccessTokensFinished() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccount::onRegisterFinished()
|
||||||
|
{
|
||||||
|
QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
|
||||||
|
Q_ASSERT( reply );
|
||||||
|
bool ok;
|
||||||
|
const QVariantMap resp = parseReply( reply, ok );
|
||||||
|
if ( !ok )
|
||||||
|
{
|
||||||
|
emit registerFinished( false, resp.value( "errormsg" ).toString() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit registerFinished( true, QString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccount::onPasswordLoginFinished( QNetworkReply* reply, const QString& username )
|
||||||
|
{
|
||||||
|
Q_ASSERT( reply );
|
||||||
|
bool ok;
|
||||||
|
const QVariantMap resp = parseReply( reply, ok );
|
||||||
|
if ( !ok )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QByteArray authenticationToken = resp.value( "message" ).toMap().value( "authtoken" ).toMap().value("token").toByteArray();
|
||||||
|
|
||||||
|
QVariantHash creds = credentials();
|
||||||
|
creds[ "username" ] = username;
|
||||||
|
creds[ "authtoken" ] = authenticationToken;
|
||||||
|
setCredentials( creds );
|
||||||
|
syncConfig();
|
||||||
|
|
||||||
|
if ( !authenticationToken.isEmpty() )
|
||||||
|
{
|
||||||
|
// We're succesful! Now log in with our authtoken for access
|
||||||
|
fetchAccessTokens();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccount::onFetchAccessTokensFinished()
|
||||||
|
{
|
||||||
|
QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
|
||||||
|
Q_ASSERT( reply );
|
||||||
|
bool ok;
|
||||||
|
const QVariantMap resp = parseReply( reply, ok );
|
||||||
|
if ( !ok )
|
||||||
|
{
|
||||||
|
if ( resp["code"].toInt() == 140 )
|
||||||
|
{
|
||||||
|
tLog() << "Expired credentials, need to reauthenticate with password";
|
||||||
|
QVariantHash creds = credentials();
|
||||||
|
creds.remove( "authtoken" );
|
||||||
|
setCredentials( creds );
|
||||||
|
syncConfig();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tLog() << "Unable to fetch access tokens";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantHash creds = credentials();
|
||||||
|
creds[ "accesstokens" ] = resp[ "message" ].toMap()[ "accesstokens" ];
|
||||||
|
setCredentials( creds );
|
||||||
|
syncConfig();
|
||||||
|
|
||||||
|
emit accessTokensFetched();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString
|
||||||
|
HatchetAccount::authUrlForService( const Service &service ) const
|
||||||
|
{
|
||||||
|
return m_extraAuthUrls.value( service, QString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccount::authUrlDiscovered( Service service, const QString &authUrl )
|
||||||
|
{
|
||||||
|
m_extraAuthUrls[ service ] = authUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QNetworkReply*
|
||||||
|
HatchetAccount::buildRequest( const QString& command, const QVariantMap& params ) const
|
||||||
|
{
|
||||||
|
QJson::Serializer s;
|
||||||
|
const QByteArray msgJson = s.serialize( params );
|
||||||
|
|
||||||
|
QNetworkRequest req( QUrl( QString( "%1/%2" ).arg( AUTH_SERVER ).arg( command ) ) );
|
||||||
|
req.setHeader( QNetworkRequest::ContentTypeHeader, "application/json; charset=utf-8" );
|
||||||
|
QNetworkReply* reply = TomahawkUtils::nam()->post( req, msgJson );
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QVariantMap
|
||||||
|
HatchetAccount::parseReply( QNetworkReply* reply, bool& okRet ) const
|
||||||
|
{
|
||||||
|
QVariantMap resp;
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if ( reply->error() != QNetworkReply::NoError )
|
||||||
|
{
|
||||||
|
tLog() << "Network error in command:" << reply->error() << reply->errorString();
|
||||||
|
okRet = false;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJson::Parser p;
|
||||||
|
bool ok;
|
||||||
|
resp = p.parse( reply, &ok ).toMap();
|
||||||
|
|
||||||
|
if ( !ok || resp.value( "error", false ).toBool() )
|
||||||
|
{
|
||||||
|
tLog() << "Error from tomahawk server response, or in parsing from json:" << resp.value( "errormsg" ) << resp;
|
||||||
|
okRet = false;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
tLog() << "Got reply" << resp.keys();
|
||||||
|
tLog() << "Got reply" << resp.values();
|
||||||
|
okRet = true;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_EXPORT_PLUGIN2( Tomahawk::Accounts::AccountFactory, Tomahawk::Accounts::HatchetAccountFactory )
|
129
src/accounts/hatchet/account/HatchetAccount.h
Normal file
129
src/accounts/hatchet/account/HatchetAccount.h
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TOMAHAWK_ACCOUNT_H
|
||||||
|
#define TOMAHAWK_ACCOUNT_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <accounts/Account.h>
|
||||||
|
#include <accounts/AccountDllMacro.h>
|
||||||
|
|
||||||
|
class QNetworkReply;
|
||||||
|
|
||||||
|
class HatchetSipPlugin;
|
||||||
|
|
||||||
|
namespace Tomahawk
|
||||||
|
{
|
||||||
|
namespace Accounts
|
||||||
|
{
|
||||||
|
|
||||||
|
class HatchetAccountConfig;
|
||||||
|
|
||||||
|
class ACCOUNTDLLEXPORT HatchetAccountFactory : public AccountFactory
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_INTERFACES( Tomahawk::Accounts::AccountFactory )
|
||||||
|
public:
|
||||||
|
HatchetAccountFactory();
|
||||||
|
virtual ~HatchetAccountFactory();
|
||||||
|
|
||||||
|
virtual QString factoryId() const { return "hatchetaccount"; }
|
||||||
|
virtual QString prettyName() const { return "Hatchet"; }
|
||||||
|
virtual QString description() const { return tr( "Connect to your Hatchet account" ); }
|
||||||
|
virtual bool isUnique() const { return true; }
|
||||||
|
AccountTypes types() const { return AccountTypes( SipType ); };
|
||||||
|
// virtual bool allowUserCreation() const { return false; }
|
||||||
|
#ifndef ENABLE_HEADLESS
|
||||||
|
virtual QPixmap icon() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
virtual Account* createAccount ( const QString& pluginId = QString() );
|
||||||
|
};
|
||||||
|
|
||||||
|
class ACCOUNTDLLEXPORT HatchetAccount : public Account
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum Service {
|
||||||
|
Facebook = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
HatchetAccount( const QString &accountId );
|
||||||
|
virtual ~HatchetAccount();
|
||||||
|
|
||||||
|
static HatchetAccount* instance();
|
||||||
|
|
||||||
|
QPixmap icon() const;
|
||||||
|
|
||||||
|
void authenticate();
|
||||||
|
void deauthenticate();
|
||||||
|
bool isAuthenticated() const;
|
||||||
|
|
||||||
|
void setConnectionState( Account::ConnectionState connectionState );
|
||||||
|
ConnectionState connectionState() const;
|
||||||
|
|
||||||
|
|
||||||
|
virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin() { return Tomahawk::InfoSystem::InfoPluginPtr(); }
|
||||||
|
SipPlugin* sipPlugin();
|
||||||
|
|
||||||
|
AccountConfigWidget* configurationWidget();
|
||||||
|
QWidget* aclWidget() { return 0; }
|
||||||
|
|
||||||
|
QString username() const;
|
||||||
|
|
||||||
|
void fetchAccessTokens();
|
||||||
|
|
||||||
|
QString authUrlForService( const Service& service ) const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void deauthenticated();
|
||||||
|
void accessTokensFetched();
|
||||||
|
void registerFinished( bool successful, const QString& msg );
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onRegisterFinished();
|
||||||
|
void onPasswordLoginFinished( QNetworkReply*, const QString& username );
|
||||||
|
void onFetchAccessTokensFinished();
|
||||||
|
|
||||||
|
void authUrlDiscovered( Tomahawk::Accounts::HatchetAccount::Service service, const QString& authUrl );
|
||||||
|
private:
|
||||||
|
QByteArray authToken() const;
|
||||||
|
|
||||||
|
void doRegister( const QString& username, const QString& password, const QString& email );
|
||||||
|
void loginWithPassword( const QString& username, const QString& password );
|
||||||
|
|
||||||
|
QNetworkReply* buildRequest( const QString& command, const QVariantMap& params ) const;
|
||||||
|
QVariantMap parseReply( QNetworkReply* reply, bool& ok ) const;
|
||||||
|
|
||||||
|
QWeakPointer<HatchetAccountConfig> m_configWidget;
|
||||||
|
|
||||||
|
Account::ConnectionState m_state;
|
||||||
|
|
||||||
|
QWeakPointer< HatchetSipPlugin > m_tomahawkSipPlugin;
|
||||||
|
QHash< Service, QString > m_extraAuthUrls;
|
||||||
|
|
||||||
|
static HatchetAccount* s_instance;
|
||||||
|
friend class HatchetAccountConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
207
src/accounts/hatchet/account/HatchetAccountConfig.cpp
Normal file
207
src/accounts/hatchet/account/HatchetAccountConfig.cpp
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "HatchetAccountConfig.h"
|
||||||
|
#include "HatchetAccount.h"
|
||||||
|
#include "utils/TomahawkUtils.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
|
#include "ui_HatchetAccountConfig.h"
|
||||||
|
|
||||||
|
using namespace Tomahawk;
|
||||||
|
using namespace Accounts;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
enum ButtonAction {
|
||||||
|
Login,
|
||||||
|
Register,
|
||||||
|
Logout
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
HatchetAccountConfig::HatchetAccountConfig( HatchetAccount* account )
|
||||||
|
: AccountConfigWidget( 0 )
|
||||||
|
, m_ui( new Ui::HatchetAccountConfig )
|
||||||
|
, m_account( account )
|
||||||
|
{
|
||||||
|
Q_ASSERT( m_account );
|
||||||
|
|
||||||
|
m_ui->setupUi( this );
|
||||||
|
|
||||||
|
m_ui->emailLabel->hide();
|
||||||
|
m_ui->emailEdit->hide();
|
||||||
|
|
||||||
|
connect( m_ui->registerbutton, SIGNAL( clicked( bool ) ), this, SLOT( registerClicked() ) );
|
||||||
|
connect( m_ui->loginOrRegisterButton, SIGNAL( clicked( bool ) ), this, SLOT( loginOrRegister() ) );
|
||||||
|
|
||||||
|
connect( m_ui->usernameEdit, SIGNAL( textChanged( QString ) ), this, SLOT( fieldsChanged() ) );
|
||||||
|
connect( m_ui->passwordEdit, SIGNAL( textChanged( QString ) ), this, SLOT( fieldsChanged() ) );
|
||||||
|
connect( m_ui->emailEdit, SIGNAL( textChanged( QString ) ), this, SLOT( fieldsChanged() ) );
|
||||||
|
|
||||||
|
connect( m_account, SIGNAL( registerFinished( bool, QString ) ), this, SLOT( registerFinished( bool, QString ) ) );
|
||||||
|
connect( m_account, SIGNAL( deauthenticated() ), this, SLOT( showLoggedOut() ) );
|
||||||
|
connect( m_account, SIGNAL( accessTokensFetched() ), this, SLOT( accountInfoUpdated() ) );
|
||||||
|
|
||||||
|
if ( !m_account->authToken().isEmpty() )
|
||||||
|
accountInfoUpdated();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_ui->usernameEdit->setText( m_account->username() );
|
||||||
|
showLoggedOut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HatchetAccountConfig::~HatchetAccountConfig()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccountConfig::registerClicked()
|
||||||
|
{
|
||||||
|
m_ui->registerbutton->hide();
|
||||||
|
|
||||||
|
m_ui->emailLabel->show();
|
||||||
|
m_ui->emailEdit->show();
|
||||||
|
m_ui->loginOrRegisterButton->setText( tr( "Register" ) );
|
||||||
|
m_ui->loginOrRegisterButton->setProperty( "action", Register );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccountConfig::loginOrRegister()
|
||||||
|
{
|
||||||
|
const ButtonAction action = static_cast< ButtonAction>( m_ui->loginOrRegisterButton->property( "action" ).toInt() );
|
||||||
|
|
||||||
|
if ( action == Login )
|
||||||
|
{
|
||||||
|
// Log in mode
|
||||||
|
m_account->loginWithPassword( m_ui->usernameEdit->text(), m_ui->passwordEdit->text() );
|
||||||
|
}
|
||||||
|
else if ( action == Register )
|
||||||
|
{
|
||||||
|
// Register since the use clicked register and just entered his info
|
||||||
|
const QString username = m_ui->usernameEdit->text();
|
||||||
|
const QString password = m_ui->passwordEdit->text();
|
||||||
|
const QString email = m_ui->emailEdit->text();
|
||||||
|
m_account->doRegister( username, password, email );
|
||||||
|
}
|
||||||
|
else if ( action == Logout )
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
m_ui->usernameEdit->clear();
|
||||||
|
m_ui->passwordEdit->clear();
|
||||||
|
|
||||||
|
QVariantHash creds = m_account->credentials();
|
||||||
|
creds.clear();
|
||||||
|
m_account->setCredentials( creds );
|
||||||
|
m_account->sync();
|
||||||
|
m_account->deauthenticate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccountConfig::fieldsChanged()
|
||||||
|
{
|
||||||
|
const QString username = m_ui->usernameEdit->text();
|
||||||
|
const QString password = m_ui->passwordEdit->text();
|
||||||
|
const QString email = m_ui->emailEdit->text();
|
||||||
|
|
||||||
|
const ButtonAction action = static_cast< ButtonAction>( m_ui->loginOrRegisterButton->property( "action" ).toInt() );
|
||||||
|
|
||||||
|
m_ui->loginOrRegisterButton->setEnabled( !username.isEmpty() && !password.isEmpty() && ( action == Login || !email.isEmpty() ) );
|
||||||
|
|
||||||
|
m_ui->errorLabel->clear();
|
||||||
|
|
||||||
|
if ( action == Login )
|
||||||
|
m_ui->loginOrRegisterButton->setText( tr( "Login" ) );
|
||||||
|
else if ( action == Register )
|
||||||
|
m_ui->loginOrRegisterButton->setText( tr( "Register" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccountConfig::registerFinished( bool success, const QString& error )
|
||||||
|
{
|
||||||
|
if ( success )
|
||||||
|
{
|
||||||
|
showLoggedOut();
|
||||||
|
m_ui->errorLabel->setText( tr( "An email has been sent to activate your account" ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_ui->loginOrRegisterButton->setText( "Failed" );
|
||||||
|
m_ui->loginOrRegisterButton->setEnabled( false );
|
||||||
|
m_ui->errorLabel->setText( error );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccountConfig::showLoggedIn()
|
||||||
|
{
|
||||||
|
m_ui->registerbutton->hide();
|
||||||
|
m_ui->usernameLabel->hide();
|
||||||
|
m_ui->usernameEdit->hide();
|
||||||
|
m_ui->emailLabel->hide();
|
||||||
|
m_ui->emailEdit->hide();
|
||||||
|
m_ui->passwordLabel->hide();
|
||||||
|
m_ui->passwordEdit->hide();
|
||||||
|
|
||||||
|
m_ui->loggedInLabel->setText( tr( "Logged in as: %1" ).arg( m_account->username() ) );
|
||||||
|
m_ui->loggedInLabel->show();
|
||||||
|
|
||||||
|
m_ui->errorLabel->clear();
|
||||||
|
m_ui->errorLabel->hide();
|
||||||
|
|
||||||
|
m_ui->loginOrRegisterButton->setText( "Log out" );
|
||||||
|
m_ui->loginOrRegisterButton->setProperty( "action", Logout );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccountConfig::showLoggedOut()
|
||||||
|
{
|
||||||
|
m_ui->emailEdit->hide();
|
||||||
|
m_ui->emailLabel->hide();
|
||||||
|
|
||||||
|
m_ui->registerbutton->show();
|
||||||
|
m_ui->usernameLabel->show();
|
||||||
|
m_ui->usernameEdit->show();
|
||||||
|
m_ui->passwordLabel->show();
|
||||||
|
m_ui->passwordEdit->show();
|
||||||
|
|
||||||
|
m_ui->loggedInLabel->clear();
|
||||||
|
m_ui->loggedInLabel->hide();
|
||||||
|
|
||||||
|
m_ui->errorLabel->clear();
|
||||||
|
|
||||||
|
m_ui->loginOrRegisterButton->setText( "Login" );
|
||||||
|
m_ui->loginOrRegisterButton->setProperty( "action", Login );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetAccountConfig::accountInfoUpdated()
|
||||||
|
{
|
||||||
|
showLoggedIn();
|
||||||
|
return;
|
||||||
|
}
|
65
src/accounts/hatchet/account/HatchetAccountConfig.h
Normal file
65
src/accounts/hatchet/account/HatchetAccountConfig.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TOMAHAWK_ACCOUNT_CONFIG_H
|
||||||
|
#define TOMAHAWK_ACCOUNT_CONFIG_H
|
||||||
|
|
||||||
|
#include <accounts/AccountConfigWidget.h>
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
|
class QNetworkReply;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class HatchetAccountConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Tomahawk {
|
||||||
|
namespace Accounts {
|
||||||
|
|
||||||
|
class HatchetAccount;
|
||||||
|
|
||||||
|
class HatchetAccountConfig : public AccountConfigWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit HatchetAccountConfig( HatchetAccount* account );
|
||||||
|
virtual ~HatchetAccountConfig();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void registerClicked();
|
||||||
|
void loginOrRegister();
|
||||||
|
|
||||||
|
void registerFinished( bool success, const QString& error );
|
||||||
|
|
||||||
|
void fieldsChanged();
|
||||||
|
|
||||||
|
void showLoggedIn();
|
||||||
|
void showLoggedOut();
|
||||||
|
|
||||||
|
void accountInfoUpdated();
|
||||||
|
private:
|
||||||
|
Ui::HatchetAccountConfig* m_ui;
|
||||||
|
HatchetAccount* m_account;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
150
src/accounts/hatchet/account/HatchetAccountConfig.ui
Normal file
150
src/accounts/hatchet/account/HatchetAccountConfig.ui
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>HatchetAccountConfig</class>
|
||||||
|
<widget class="QWidget" name="HatchetAccountConfig">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>301</width>
|
||||||
|
<height>404</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../resources.qrc">:/hatchet-account/hatchet-icon-512x512.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Connect to your Hatchet account</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="registerbutton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Register for a free account</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="loggedInLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="credentialsLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="emailLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Email:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="emailEdit">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Enter email to use</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="usernameLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Username</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="usernameEdit">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Hatchet username</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="passwordLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Password:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="passwordEdit">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="errorLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="loginOrRegisterButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Login</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../resources.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
14
src/accounts/hatchet/admin/certs/dreamcatcher.pem
Normal file
14
src/accounts/hatchet/admin/certs/dreamcatcher.pem
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyT6j9B1hiRHwV96BSZJp
|
||||||
|
vLnGS0p6h1fxJiVGOjpcct/pA1rfVW66LTC7seYT6mF15flccIn5H8srAvH2a57S
|
||||||
|
uCMHDrHkQIoNDoOf+Ersw4tYzVYv+5h8IN9apYr6iqfT7rn3Fzb5oEB+GqcDurX3
|
||||||
|
4aaDjm+Wq0QjJAZf0fOaKor0ASejkj6EywpaHLwj51DKtf6SYbDEf52vDOzsDDnx
|
||||||
|
2AzVeqzPNFnnau6/v7rCi081b33qOrbJBtJjSNAJcM3iVf465k8KP2VD8nX3wzwT
|
||||||
|
9H0TEp67UMm0lz2i6gSAyEcIR2FNdTjVa1ZHYF2tnOihFDu0H4U4/4mPswpNNdOp
|
||||||
|
mtc5WxxK5ouKqxD8ArSoclmZMybIBbL0lLRjo4VC/olfbd1RQ57L9ETtNIf0xxKU
|
||||||
|
aweUkfWyJfU5ueaSlBaGoKSGugqp50ql3Td0m2JnJmaopdSi12L3EdlaO0+/OL3f
|
||||||
|
0aXbtnsZXlIHoq7FBEYcLhCNbwEeceV5Cveb5Os8w2331jkgpcPoXQFOtIVyva2B
|
||||||
|
3RadI0aALIbX5Tt0/AcbLeq10BJH8Ny2RSrhF2cxkjXEwQ68OUbCv1U4Si+EL44E
|
||||||
|
tctg8zj9rB8SG+miE18cXaQEUxA/olOU/Axkm8dLLLTxqWsD3VQYDxBgBemaY1OT
|
||||||
|
O32yipB9ko1sLCx6ZaQQ56sCAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----
|
44
src/accounts/hatchet/admin/certs/startcomroot.pem
Normal file
44
src/accounts/hatchet/admin/certs/startcomroot.pem
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
|
||||||
|
MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
|
||||||
|
Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
|
||||||
|
dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
|
||||||
|
MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
|
||||||
|
U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
|
||||||
|
cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
|
||||||
|
A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
|
||||||
|
pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
|
||||||
|
OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
|
||||||
|
Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
|
||||||
|
Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
|
||||||
|
HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
|
||||||
|
Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
|
||||||
|
+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
|
||||||
|
Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
|
||||||
|
Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
|
||||||
|
26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
|
||||||
|
AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
|
||||||
|
FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
|
||||||
|
ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
|
||||||
|
LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
|
||||||
|
BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
|
||||||
|
Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
|
||||||
|
dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
|
||||||
|
cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
|
||||||
|
YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
|
||||||
|
dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
|
||||||
|
bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
|
||||||
|
YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
|
||||||
|
TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
|
||||||
|
9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
|
||||||
|
jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
|
||||||
|
FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
|
||||||
|
ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
|
||||||
|
ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
|
||||||
|
EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
|
||||||
|
L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
|
||||||
|
yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
|
||||||
|
O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
|
||||||
|
um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
|
||||||
|
NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
|
||||||
|
-----END CERTIFICATE-----
|
BIN
src/accounts/hatchet/admin/icons/hatchet-icon-512x512.png
Normal file
BIN
src/accounts/hatchet/admin/icons/hatchet-icon-512x512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
37
src/accounts/hatchet/cmake/Modules/FindQCA2.cmake
Normal file
37
src/accounts/hatchet/cmake/Modules/FindQCA2.cmake
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# - Try to find QCA2 (Qt Cryptography Architecture 2)
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# QCA2_FOUND - system has QCA2
|
||||||
|
# QCA2_INCLUDE_DIR - the QCA2 include directory
|
||||||
|
# QCA2_LIBRARIES - the libraries needed to use QCA2
|
||||||
|
# QCA2_DEFINITIONS - Compiler switches required for using QCA2
|
||||||
|
#
|
||||||
|
# use pkg-config to get the directories and then use these values
|
||||||
|
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||||
|
|
||||||
|
# Copyright (c) 2006, Michael Larouche, <michael.larouche@kdemail.net>
|
||||||
|
#
|
||||||
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||||
|
|
||||||
|
if (NOT WIN32)
|
||||||
|
find_package(PkgConfig)
|
||||||
|
pkg_check_modules(PC_QCA2 qca2)
|
||||||
|
set(QCA2_DEFINITIONS ${PC_QCA2_CFLAGS_OTHER})
|
||||||
|
endif (NOT WIN32)
|
||||||
|
|
||||||
|
find_library(QCA2_LIBRARIES
|
||||||
|
NAMES qca
|
||||||
|
HINTS ${PC_QCA2_LIBDIR} ${PC_QCA2_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_path(QCA2_INCLUDE_DIR qca.h
|
||||||
|
HINTS ${PC_QCA2_INCLUDEDIR} ${PC_QCA2_INCLUDE_DIRS}
|
||||||
|
PATH_SUFFIXES QtCrypto
|
||||||
|
PATHS /usr/local/lib/qca.framework/Headers/
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(QCA2 DEFAULT_MSG QCA2_LIBRARIES QCA2_INCLUDE_DIR)
|
||||||
|
|
||||||
|
mark_as_advanced(QCA2_INCLUDE_DIR QCA2_LIBRARIES)
|
7
src/accounts/hatchet/resources.qrc
Normal file
7
src/accounts/hatchet/resources.qrc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/hatchet-account">
|
||||||
|
<file alias="hatchet-icon-512x512.png">admin/icons/hatchet-icon-512x512.png</file>
|
||||||
|
<file alias="dreamcatcher.pem">admin/certs/dreamcatcher.pem</file>
|
||||||
|
<file alias="startcomroot.pem">admin/certs/startcomroot.pem</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
554
src/accounts/hatchet/sip/HatchetSip.cpp
Normal file
554
src/accounts/hatchet/sip/HatchetSip.cpp
Normal file
@@ -0,0 +1,554 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "HatchetSip.h"
|
||||||
|
|
||||||
|
#include "account/HatchetAccount.h"
|
||||||
|
#include "WebSocketThreadController.h"
|
||||||
|
//#include "WebSocket.h"
|
||||||
|
|
||||||
|
#include <database/Database.h>
|
||||||
|
#include <database/DatabaseImpl.h>
|
||||||
|
#include <database/DatabaseCommand_LoadOps.h>
|
||||||
|
#include <network/ControlConnection.h>
|
||||||
|
#include <network/Servent.h>
|
||||||
|
#include <sip/PeerInfo.h>
|
||||||
|
#include <utils/Logger.h>
|
||||||
|
#include <SourceList.h>
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QUuid>
|
||||||
|
#include <QtCrypto>
|
||||||
|
|
||||||
|
HatchetSipPlugin::HatchetSipPlugin( Tomahawk::Accounts::Account *account )
|
||||||
|
: SipPlugin( account )
|
||||||
|
, m_sipState( Closed )
|
||||||
|
, m_version( 0 )
|
||||||
|
, m_publicKey( 0 )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
|
||||||
|
connect( m_account, SIGNAL( accessTokensFetched() ), this, SLOT( connectWebSocket() ) );
|
||||||
|
connect( Servent::instance(), SIGNAL( dbSyncTriggered() ), this, SLOT( dbSyncTriggered() ));
|
||||||
|
|
||||||
|
QFile pemFile( ":/hatchet-account/dreamcatcher.pem" );
|
||||||
|
pemFile.open( QIODevice::ReadOnly );
|
||||||
|
tLog() << Q_FUNC_INFO << "certs/dreamcatcher.pem: " << pemFile.readAll();
|
||||||
|
pemFile.close();
|
||||||
|
pemFile.open( QIODevice::ReadOnly );
|
||||||
|
QCA::ConvertResult conversionResult;
|
||||||
|
QCA::PublicKey publicKey = QCA::PublicKey::fromPEM(pemFile.readAll(), &conversionResult);
|
||||||
|
if ( QCA::ConvertGood != conversionResult )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "INVALID PUBKEY READ";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_publicKey = new QCA::PublicKey( publicKey );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HatchetSipPlugin::~HatchetSipPlugin()
|
||||||
|
{
|
||||||
|
if ( m_webSocketThreadController )
|
||||||
|
{
|
||||||
|
m_webSocketThreadController->quit();
|
||||||
|
m_webSocketThreadController->wait( 60000 );
|
||||||
|
|
||||||
|
delete m_webSocketThreadController;
|
||||||
|
m_webSocketThreadController = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sipState = Closed;
|
||||||
|
|
||||||
|
hatchetAccount()->setConnectionState( Tomahawk::Accounts::Account::Disconnected );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
HatchetSipPlugin::isValid() const
|
||||||
|
{
|
||||||
|
return m_account->enabled() && m_account->isAuthenticated() && m_publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::sendSipInfo(const Tomahawk::peerinfo_ptr& receiver, const SipInfo& info)
|
||||||
|
{
|
||||||
|
const QString dbid = receiver->data().toMap().value( "dbid" ).toString();
|
||||||
|
tLog() << Q_FUNC_INFO << "Send local info to " << receiver->friendlyName() << "(" << dbid << ") we are" << info.nodeId() << "with offerkey " << info.key();
|
||||||
|
|
||||||
|
QVariantMap sendMap;
|
||||||
|
sendMap[ "command" ] = "authorize-peer";
|
||||||
|
sendMap[ "dbid" ] = dbid;
|
||||||
|
sendMap[ "offerkey" ] = info.key();
|
||||||
|
|
||||||
|
|
||||||
|
if ( !sendBytes( sendMap ) )
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed sending message";
|
||||||
|
}
|
||||||
|
|
||||||
|
Tomahawk::Accounts::HatchetAccount*
|
||||||
|
HatchetSipPlugin::hatchetAccount() const
|
||||||
|
{
|
||||||
|
return qobject_cast< Tomahawk::Accounts::HatchetAccount* >( m_account );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::connectPlugin()
|
||||||
|
{
|
||||||
|
if ( !m_account->isAuthenticated() )
|
||||||
|
{
|
||||||
|
//FIXME: Prompt user for password?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_webSocketThreadController = QPointer< WebSocketThreadController >( new WebSocketThreadController( this ) );
|
||||||
|
|
||||||
|
hatchetAccount()->setConnectionState( Tomahawk::Accounts::Account::Connecting );
|
||||||
|
hatchetAccount()->fetchAccessTokens();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::disconnectPlugin()
|
||||||
|
{
|
||||||
|
if ( m_webSocketThreadController )
|
||||||
|
{
|
||||||
|
m_webSocketThreadController->quit();
|
||||||
|
m_webSocketThreadController->wait( 60000 );
|
||||||
|
|
||||||
|
delete m_webSocketThreadController;
|
||||||
|
m_webSocketThreadController = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sipState = Closed;
|
||||||
|
m_version = 0;
|
||||||
|
|
||||||
|
hatchetAccount()->setConnectionState( Tomahawk::Accounts::Account::Disconnected );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////// Connection methods ////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::connectWebSocket()
|
||||||
|
{
|
||||||
|
//Other things can request access tokens, so if we're already connected there's no need to pay attention
|
||||||
|
// if ( !m_ws.isNull() )
|
||||||
|
// return;
|
||||||
|
|
||||||
|
if ( !isValid() )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Invalid state, not continuing with connection";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList tokensCreds = m_account->credentials()[ "accesstokens" ].toList();
|
||||||
|
//FIXME: Don't blindly pick the first one that matches?
|
||||||
|
QVariantMap connectVals;
|
||||||
|
foreach ( QVariant credObj, tokensCreds )
|
||||||
|
{
|
||||||
|
QVariantMap creds = credObj.toMap();
|
||||||
|
if ( creds.contains( "type" ) && creds[ "type" ].toString() == "dreamcatcher" )
|
||||||
|
{
|
||||||
|
connectVals = creds;
|
||||||
|
m_userid = creds["userid"].toString();
|
||||||
|
m_token = creds["token"].toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString url;
|
||||||
|
if ( !connectVals.isEmpty() )
|
||||||
|
url = connectVals[ "host" ].toString() + ':' + connectVals[ "port" ].toString();
|
||||||
|
|
||||||
|
if ( url.isEmpty() )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Unable to find a proper connection endpoint; bailing";
|
||||||
|
disconnectPlugin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tLog() << Q_FUNC_INFO << "Connecting to Dreamcatcher endpoint at: " << url;
|
||||||
|
|
||||||
|
m_webSocketThreadController->setUrl( url );
|
||||||
|
// connect( m_ws.data(), SIGNAL( opened() ), this, SLOT( onWsOpened() ) );
|
||||||
|
// connect( m_ws.data(), SIGNAL( failed( QString ) ), this, SLOT( onWsFailed( QString ) ) );
|
||||||
|
// connect( m_ws.data(), SIGNAL( closed( QString ) ), this, SLOT( onWsClosed( QString ) ) );
|
||||||
|
// connect( m_ws.data(), SIGNAL( message( QString ) ), this, SLOT( onWsMessage( QString ) ) );
|
||||||
|
m_webSocketThreadController->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::webSocketConnected()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "WebSocket connected";
|
||||||
|
|
||||||
|
if ( m_token.isEmpty() || !m_account->credentials().contains( "username" ) )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "access token or username is empty, aborting";
|
||||||
|
disconnectPlugin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hatchetAccount()->setConnectionState( Tomahawk::Accounts::Account::Connected );
|
||||||
|
m_sipState = AcquiringVersion;
|
||||||
|
|
||||||
|
m_uuid = QUuid::createUuid().toString();
|
||||||
|
QCA::SecureArray sa( m_uuid.toLatin1() );
|
||||||
|
QCA::SecureArray result = m_publicKey->encrypt( sa, QCA::EME_PKCS1_OAEP );
|
||||||
|
|
||||||
|
tLog() << Q_FUNC_INFO << "uuid:" << m_uuid << ", size of uuid:" << m_uuid.size() << ", size of sa:" << sa.size() << ", size of result:" << result.size();
|
||||||
|
|
||||||
|
QVariantMap nonceVerMap;
|
||||||
|
nonceVerMap[ "version" ] = VERSION;
|
||||||
|
nonceVerMap[ "nonce" ] = QString( result.toByteArray().toBase64() );
|
||||||
|
sendBytes( nonceVerMap );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::webSocketDisconnected()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "WebSocket disconnected";
|
||||||
|
m_sipState = Closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
HatchetSipPlugin::sendBytes( const QVariantMap& jsonMap ) const
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
if ( m_sipState == Closed )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "was told to send bytes on a closed connection, not gonna do it";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJson::Serializer serializer;
|
||||||
|
QByteArray bytes = serializer.serialize( jsonMap );
|
||||||
|
if ( bytes.isEmpty() )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "could not serialize register structure to JSON";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tLog() << Q_FUNC_INFO << "Sending bytes of size" << bytes.size();
|
||||||
|
emit rawBytes( bytes );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::onWsFailed( const QString &msg )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "WebSocket failed with message: " << msg;
|
||||||
|
disconnectPlugin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::onWsClosed( const QString &msg )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "WebSocket closed with message: " << msg;
|
||||||
|
disconnectPlugin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::messageReceived( const QByteArray &msg )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "WebSocket message: " << msg;
|
||||||
|
|
||||||
|
QJson::Parser parser;
|
||||||
|
bool ok;
|
||||||
|
QVariant jsonVariant = parser.parse( msg, &ok );
|
||||||
|
if ( !jsonVariant.isValid() )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed to parse message back from server";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap retMap = jsonVariant.toMap();
|
||||||
|
|
||||||
|
if ( m_sipState == AcquiringVersion )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "In acquiring version state, expecting version/nonce information";
|
||||||
|
if ( !retMap.contains( "version" ) || !retMap.contains( "nonce" ) )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed to acquire version or nonce information";
|
||||||
|
disconnectPlugin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool ok = false;
|
||||||
|
int ver = retMap[ "version" ].toInt( &ok );
|
||||||
|
if ( ver == 0 || !ok )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed to acquire version information";
|
||||||
|
disconnectPlugin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( retMap[ "nonce" ].toString() != m_uuid )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed to validate nonce";
|
||||||
|
disconnectPlugin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_version = ver;
|
||||||
|
|
||||||
|
QVariantMap registerMap;
|
||||||
|
registerMap[ "command" ] = "register";
|
||||||
|
registerMap[ "userid" ] = m_userid;
|
||||||
|
registerMap[ "host" ] = Servent::instance()->externalAddress();
|
||||||
|
registerMap[ "port" ] = Servent::instance()->externalPort();
|
||||||
|
registerMap[ "token" ] = m_token;
|
||||||
|
registerMap[ "dbid" ] = Database::instance()->impl()->dbid();
|
||||||
|
registerMap[ "alias" ] = QHostInfo::localHostName();
|
||||||
|
|
||||||
|
if ( !sendBytes( registerMap ) )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed sending message";
|
||||||
|
disconnectPlugin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sipState = Registering;
|
||||||
|
}
|
||||||
|
else if ( m_sipState == Registering )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "In registering state, checking status of registration";
|
||||||
|
if ( retMap.contains( "status" ) &&
|
||||||
|
retMap[ "status" ].toString() == "success" )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Registered successfully";
|
||||||
|
m_sipState = Connected;
|
||||||
|
hatchetAccount()->setConnectionState( Tomahawk::Accounts::Account::Connected );
|
||||||
|
QTimer::singleShot(0, this, SLOT( dbSyncTriggered() ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed to register successfully";
|
||||||
|
//m_ws.data()->stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( m_sipState != Connected )
|
||||||
|
{
|
||||||
|
// ...erm?
|
||||||
|
tLog() << Q_FUNC_INFO << "Got a message from a non connected socket?";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ( !retMap.contains( "command" ) ||
|
||||||
|
!retMap[ "command" ].canConvert< QString >() )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Unable to convert and/or interepret command from server";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString command = retMap[ "command" ].toString();
|
||||||
|
|
||||||
|
if ( command == "new-peer" )
|
||||||
|
newPeer( retMap );
|
||||||
|
else if ( command == "peer-authorization" )
|
||||||
|
peerAuthorization( retMap );
|
||||||
|
else if ( command == "synclastseen" )
|
||||||
|
sendOplog( retMap );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
HatchetSipPlugin::checkKeys( QStringList keys, const QVariantMap& map ) const
|
||||||
|
{
|
||||||
|
foreach ( QString key, keys )
|
||||||
|
{
|
||||||
|
if ( !map.contains( key ) )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Did not find the value" << key << "in the new-peer structure";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////// Peer handling methods ////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::newPeer( const QVariantMap& valMap )
|
||||||
|
{
|
||||||
|
const QString username = valMap[ "username" ].toString();
|
||||||
|
const QString dbid = valMap[ "dbid" ].toString();
|
||||||
|
const QString host = valMap[ "host" ].toString();
|
||||||
|
unsigned int port = valMap[ "port" ].toUInt();
|
||||||
|
|
||||||
|
tLog() << Q_FUNC_INFO << "username:" << username << "dbid" << dbid;
|
||||||
|
|
||||||
|
QStringList keys( QStringList() << "command" << "username" << "host" << "port" << "dbid" );
|
||||||
|
if ( !checkKeys( keys, valMap ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Tomahawk::peerinfo_ptr peerInfo = Tomahawk::PeerInfo::get( this, dbid, Tomahawk::PeerInfo::AutoCreate );
|
||||||
|
peerInfo->setContactId( username );
|
||||||
|
peerInfo->setFriendlyName( username );
|
||||||
|
QVariantMap data;
|
||||||
|
data.insert( "dbid", QVariant::fromValue< QString >( dbid ) );
|
||||||
|
peerInfo->setData( data );
|
||||||
|
|
||||||
|
|
||||||
|
SipInfo sipInfo;
|
||||||
|
sipInfo.setNodeId( dbid );
|
||||||
|
if( !host.isEmpty() && port != 0 )
|
||||||
|
{
|
||||||
|
sipInfo.setHost( valMap[ "host" ].toString() );
|
||||||
|
sipInfo.setPort( valMap[ "port" ].toUInt() );
|
||||||
|
sipInfo.setVisible( true );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sipInfo.setVisible( false );
|
||||||
|
}
|
||||||
|
peerInfo->setSipInfo( sipInfo );
|
||||||
|
|
||||||
|
peerInfo->setStatus( Tomahawk::PeerInfo::Online );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::peerAuthorization( const QVariantMap& valMap )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "dbid:" << valMap[ "dbid" ].toString() << "offerkey" << valMap[ "offerkey" ].toString();
|
||||||
|
|
||||||
|
QStringList keys( QStringList() << "command" << "dbid" << "offerkey" );
|
||||||
|
if ( !checkKeys( keys, valMap ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
Tomahawk::peerinfo_ptr peerInfo = Tomahawk::PeerInfo::get( this, valMap[ "dbid" ].toString() );
|
||||||
|
if( peerInfo.isNull() )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Received a peer-authorization for a peer we don't know about";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SipInfo sipInfo = peerInfo->sipInfo();
|
||||||
|
sipInfo.setKey( valMap[ "offerkey" ].toString() );
|
||||||
|
peerInfo->setSipInfo( sipInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////// Syncing methods ////////////////////////////////////
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::dbSyncTriggered()
|
||||||
|
{
|
||||||
|
if ( m_sipState != Connected )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( !SourceList::instance() || SourceList::instance()->getLocal().isNull() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
QVariantMap sourceMap;
|
||||||
|
sourceMap[ "command" ] = "synctrigger";
|
||||||
|
const Tomahawk::source_ptr src = SourceList::instance()->getLocal();
|
||||||
|
sourceMap[ "name" ] = src->friendlyName();
|
||||||
|
sourceMap[ "alias" ] = QHostInfo::localHostName();
|
||||||
|
sourceMap[ "friendlyname" ] = src->dbFriendlyName();
|
||||||
|
|
||||||
|
if ( !sendBytes( sourceMap ) )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed sending message";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::sendOplog( const QVariantMap& valMap ) const
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
DatabaseCommand_loadOps* cmd = new DatabaseCommand_loadOps( SourceList::instance()->getLocal(), valMap[ "lastrevision" ].toString() );
|
||||||
|
connect( cmd, SIGNAL( done( QString, QString, QList< dbop_ptr > ) ), SLOT( oplogFetched( QString, QString, QList< dbop_ptr > ) ) );
|
||||||
|
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HatchetSipPlugin::oplogFetched( const QString& sinceguid, const QString& /* lastguid */, const QList< dbop_ptr > ops ) const
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
const uint_fast32_t byteMax = 1 << 25;
|
||||||
|
int currBytes = 0;
|
||||||
|
QVariantMap commandMap;
|
||||||
|
commandMap[ "command" ] = "oplog";
|
||||||
|
commandMap[ "startingrevision" ] = sinceguid;
|
||||||
|
currBytes += 60; //baseline for quotes, keys, commas, colons, etc.
|
||||||
|
QVariantList revisions;
|
||||||
|
tLog() << Q_FUNC_INFO << "Found" << ops.size() << "ops";
|
||||||
|
foreach( const dbop_ptr op, ops )
|
||||||
|
{
|
||||||
|
currBytes += 80; //baseline for quotes, keys, commas, colons, etc.
|
||||||
|
QVariantMap revMap;
|
||||||
|
revMap[ "revision" ] = op->guid;
|
||||||
|
currBytes += op->guid.length();
|
||||||
|
revMap[ "singleton" ] = op->singleton;
|
||||||
|
currBytes += 5; //true or false
|
||||||
|
revMap[ "command" ] = op->command;
|
||||||
|
currBytes += op->command.length();
|
||||||
|
currBytes += 5; //true or false
|
||||||
|
if ( op->compressed )
|
||||||
|
{
|
||||||
|
revMap[ "compressed" ] = true;
|
||||||
|
QByteArray b64 = op->payload.toBase64();
|
||||||
|
revMap[ "payload" ] = op->payload.toBase64();
|
||||||
|
currBytes += b64.length();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
revMap[ "compressed" ] = false;
|
||||||
|
revMap[ "payload" ] = op->payload;
|
||||||
|
currBytes += op->payload.length();
|
||||||
|
}
|
||||||
|
if ( currBytes >= (int)(byteMax - 1000000) ) // tack on an extra 1M for safety as it seems qjson puts in spaces
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
revisions << revMap;
|
||||||
|
}
|
||||||
|
tLog() << Q_FUNC_INFO << "Sending" << revisions.size() << "revisions";
|
||||||
|
commandMap[ "revisions" ] = revisions;
|
||||||
|
|
||||||
|
if ( !sendBytes( commandMap ) )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed sending message, attempting to send a blank message to clear sync state";
|
||||||
|
QVariantMap rescueMap;
|
||||||
|
rescueMap[ "command" ] = "oplog";
|
||||||
|
if ( !sendBytes( rescueMap ) )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed to send rescue map; state may be out-of-sync with server";
|
||||||
|
//FIXME: Do we want to disconnect and reconnect at this point to try to get sending working and clear the server state?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
95
src/accounts/hatchet/sip/HatchetSip.h
Normal file
95
src/accounts/hatchet/sip/HatchetSip.h
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TOMAHAWK_SIP_H
|
||||||
|
#define TOMAHAWK_SIP_H
|
||||||
|
|
||||||
|
#include "accounts/AccountDllMacro.h"
|
||||||
|
#include "database/Op.h"
|
||||||
|
#include "sip/SipPlugin.h"
|
||||||
|
#include "account/HatchetAccount.h"
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QtCrypto>
|
||||||
|
|
||||||
|
class WebSocketThreadController;
|
||||||
|
|
||||||
|
const int VERSION = 1;
|
||||||
|
|
||||||
|
class ACCOUNTDLLEXPORT HatchetSipPlugin : public SipPlugin
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
enum SipState {
|
||||||
|
AcquiringVersion,
|
||||||
|
Registering,
|
||||||
|
Connected,
|
||||||
|
Closed
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
HatchetSipPlugin( Tomahawk::Accounts::Account *account );
|
||||||
|
|
||||||
|
virtual ~HatchetSipPlugin();
|
||||||
|
|
||||||
|
virtual bool isValid() const;
|
||||||
|
|
||||||
|
virtual void sendSipInfo( const Tomahawk::peerinfo_ptr& receiver, const SipInfo& info );
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void connectPlugin();
|
||||||
|
void disconnectPlugin();
|
||||||
|
void checkSettings() {}
|
||||||
|
void configurationChanged() {}
|
||||||
|
void addContact( const QString &, const QString& ) {}
|
||||||
|
void sendMsg( const QString&, const SipInfo& ) {}
|
||||||
|
void webSocketConnected();
|
||||||
|
void webSocketDisconnected();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void connectWebSocket() const;
|
||||||
|
void disconnectWebSocket() const;
|
||||||
|
void authUrlDiscovered( Tomahawk::Accounts::HatchetAccount::Service service, const QString& authUrl ) const;
|
||||||
|
void rawBytes( QByteArray bytes ) const;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void dbSyncTriggered();
|
||||||
|
void messageReceived( const QByteArray& msg );
|
||||||
|
void connectWebSocket();
|
||||||
|
void onWsFailed( const QString &msg );
|
||||||
|
void onWsClosed( const QString &msg );
|
||||||
|
void oplogFetched( const QString& sinceguid, const QString& lastguid, const QList< dbop_ptr > ops ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool sendBytes( const QVariantMap& jsonMap ) const;
|
||||||
|
bool checkKeys( QStringList keys, const QVariantMap& map ) const;
|
||||||
|
void newPeer( const QVariantMap& valMap );
|
||||||
|
void peerAuthorization( const QVariantMap& valMap );
|
||||||
|
void sendOplog( const QVariantMap& valMap ) const;
|
||||||
|
Tomahawk::Accounts::HatchetAccount* hatchetAccount() const;
|
||||||
|
|
||||||
|
QPointer< WebSocketThreadController > m_webSocketThreadController;
|
||||||
|
QString m_token;
|
||||||
|
QString m_userid;
|
||||||
|
QString m_uuid;
|
||||||
|
SipState m_sipState;
|
||||||
|
int m_version;
|
||||||
|
QCA::PublicKey* m_publicKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
291
src/accounts/hatchet/sip/WebSocket.cpp
Normal file
291
src/accounts/hatchet/sip/WebSocket.cpp
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012, Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "WebSocket.h"
|
||||||
|
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
typedef typename websocketpp::lib::error_code error_code;
|
||||||
|
|
||||||
|
WebSocket::WebSocket( const QString& url )
|
||||||
|
: QObject( nullptr )
|
||||||
|
, m_url( url )
|
||||||
|
, m_outputStream()
|
||||||
|
, m_lastSocketState( QAbstractSocket::UnconnectedState )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "WebSocket constructing";
|
||||||
|
m_client = std::unique_ptr< hatchet_client >( new hatchet_client() );
|
||||||
|
m_client->set_message_handler( std::bind(&onMessage, this, std::placeholders::_1, std::placeholders::_2 ) );
|
||||||
|
m_client->register_ostream( &m_outputStream );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WebSocket::~WebSocket()
|
||||||
|
{
|
||||||
|
if ( m_connection )
|
||||||
|
m_connection.reset();
|
||||||
|
|
||||||
|
if ( m_socket )
|
||||||
|
{
|
||||||
|
if ( m_socket->state() == QAbstractSocket::ConnectedState )
|
||||||
|
{
|
||||||
|
QObject::disconnect( m_socket, SIGNAL( stateChanged( QAbstractSocket::SocketState ) ) );
|
||||||
|
m_socket->disconnectFromHost();
|
||||||
|
QObject::connect( m_socket, SIGNAL( disconnected() ), m_socket, SLOT( deleteLater() ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_socket->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_client.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocket::setUrl( const QString &url )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Setting url to" << url;
|
||||||
|
if ( m_url == url )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( m_socket && m_socket->isEncrypted() )
|
||||||
|
reconnectWs();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocket::connectWs()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Connecting";
|
||||||
|
if ( m_socket )
|
||||||
|
{
|
||||||
|
if ( m_socket->isEncrypted() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( m_socket->state() == QAbstractSocket::ClosingState )
|
||||||
|
QMetaObject::invokeMethod( this, "connectWs", Qt::QueuedConnection );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tLog() << Q_FUNC_INFO << "Establishing new connection";
|
||||||
|
m_socket = QPointer< QSslSocket >( new QSslSocket( nullptr ) );
|
||||||
|
m_socket->addCaCertificate( QSslCertificate::fromPath( ":/hatchet-account/startcomroot.pem").first() );
|
||||||
|
QObject::connect( m_socket, SIGNAL( stateChanged( QAbstractSocket::SocketState ) ), SLOT( socketStateChanged( QAbstractSocket::SocketState ) ) );
|
||||||
|
QObject::connect( m_socket, SIGNAL( sslErrors( const QList< QSslError >& ) ), SLOT( sslErrors( const QList< QSslError >& ) ) );
|
||||||
|
QObject::connect( m_socket, SIGNAL( encrypted() ), SLOT( encrypted() ) );
|
||||||
|
QObject::connect( m_socket, SIGNAL( readyRead() ), SLOT( socketReadyRead() ) );
|
||||||
|
m_socket->connectToHostEncrypted( m_url.host(), m_url.port() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocket::disconnectWs()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Disconnecting";
|
||||||
|
m_outputStream.seekg( std::ios_base::end );
|
||||||
|
m_outputStream.seekp( std::ios_base::end );
|
||||||
|
if ( m_connection )
|
||||||
|
m_connection.reset();
|
||||||
|
m_queuedMessagesToSend.empty();
|
||||||
|
m_socket->disconnectFromHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocket::reconnectWs()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Reconnecting";
|
||||||
|
QMetaObject::invokeMethod( this, "disconnectWs", Qt::QueuedConnection );
|
||||||
|
QMetaObject::invokeMethod( this, "connectWs", Qt::QueuedConnection );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocket::socketStateChanged( QAbstractSocket::SocketState state )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Socket state changed to" << state;
|
||||||
|
switch ( state )
|
||||||
|
{
|
||||||
|
case QAbstractSocket::ClosingState:
|
||||||
|
if ( m_lastSocketState == QAbstractSocket::ClosingState )
|
||||||
|
{
|
||||||
|
// It seems like it does not actually properly close, so force it
|
||||||
|
tLog() << Q_FUNC_INFO << "Got a double closing state, cleaning up and emitting disconnected";
|
||||||
|
m_socket->deleteLater();
|
||||||
|
m_lastSocketState = QAbstractSocket::UnconnectedState;
|
||||||
|
emit disconnected();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::UnconnectedState:
|
||||||
|
if ( m_lastSocketState == QAbstractSocket::UnconnectedState )
|
||||||
|
return;
|
||||||
|
tLog() << Q_FUNC_INFO << "Socket now unconnected, cleaning up and emitting disconnected";
|
||||||
|
m_socket->deleteLater();
|
||||||
|
m_lastSocketState = QAbstractSocket::UnconnectedState;
|
||||||
|
emit disconnected();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
m_lastSocketState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocket::sslErrors( const QList< QSslError >& errors )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Encountered errors when trying to connect via SSL";
|
||||||
|
foreach( QSslError error, errors )
|
||||||
|
tLog() << Q_FUNC_INFO << "Error: " << error.errorString();
|
||||||
|
QMetaObject::invokeMethod( this, "disconnectWs", Qt::QueuedConnection );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocket::encrypted()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Encrypted connection to Hatchet established";
|
||||||
|
error_code ec;
|
||||||
|
// Adjust wss:// to ws:// in the URL so it doesn't complain that the transport isn't encrypted
|
||||||
|
QString url = m_url.toString();
|
||||||
|
if ( url.startsWith( "wss") )
|
||||||
|
url.remove( 2, 1 );
|
||||||
|
m_connection = m_client->get_connection( url.toStdString(), ec );
|
||||||
|
if ( !m_connection )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Got error creating WS connection, error is:" << QString::fromStdString( ec.message() );
|
||||||
|
disconnectWs();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_client->connect( m_connection );
|
||||||
|
QMetaObject::invokeMethod( this, "readOutput", Qt::QueuedConnection );
|
||||||
|
emit connected();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocket::readOutput()
|
||||||
|
{
|
||||||
|
if ( !m_connection )
|
||||||
|
return;
|
||||||
|
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
|
||||||
|
std::string outputString = m_outputStream.str();
|
||||||
|
if ( outputString.size() > 0 )
|
||||||
|
{
|
||||||
|
m_outputStream.str("");
|
||||||
|
|
||||||
|
tLog() << Q_FUNC_INFO << "Got string of size" << outputString.size() << "from ostream";
|
||||||
|
qint64 sizeWritten = m_socket->write( outputString.data(), outputString.size() );
|
||||||
|
tLog() << Q_FUNC_INFO << "Wrote" << sizeWritten << "bytes to the socket";
|
||||||
|
if ( sizeWritten == -1 )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Error during writing, closing connection";
|
||||||
|
QMetaObject::invokeMethod( this, "disconnectWs", Qt::QueuedConnection );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_queuedMessagesToSend.size() )
|
||||||
|
{
|
||||||
|
if ( m_connection->get_state() == websocketpp::session::state::open )
|
||||||
|
{
|
||||||
|
foreach( QByteArray message, m_queuedMessagesToSend )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Sending queued message of size" << message.size();
|
||||||
|
m_connection->send( std::string( message.constData(), message.size() ), websocketpp::frame::opcode::TEXT );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_queuedMessagesToSend.clear();
|
||||||
|
QMetaObject::invokeMethod( this, "readOutput", Qt::QueuedConnection );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
QTimer::singleShot( 200, this, SLOT( readOutput() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocket::socketReadyRead()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
|
||||||
|
if ( !m_socket || !m_socket->isEncrypted() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( !m_socket->isValid() )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Socket appears to no longer be valid. Something is wrong; disconnecting";
|
||||||
|
QMetaObject::invokeMethod( this, "disconnectWs", Qt::QueuedConnection );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( qint64 bytes = m_socket->bytesAvailable() )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Bytes available:" << bytes;
|
||||||
|
QByteArray buf;
|
||||||
|
buf.resize( bytes );
|
||||||
|
qint64 bytesRead = m_socket->read( buf.data(), bytes );
|
||||||
|
tLog() << Q_FUNC_INFO << "Bytes read:" << bytesRead; // << ", content is" << websocketpp::utility::to_hex( buf.constData(), bytesRead ).data();
|
||||||
|
if ( bytesRead != bytes )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Error occurred during socket read. Something is wrong; disconnecting";
|
||||||
|
QMetaObject::invokeMethod( this, "disconnectWs", Qt::QueuedConnection );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::stringstream ss( std::string( buf.constData(), bytesRead ) );
|
||||||
|
ss >> *m_connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod( this, "readOutput", Qt::QueuedConnection );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocket::encodeMessage( const QByteArray &bytes )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Encoding message"; //, message is" << bytes.constData();
|
||||||
|
if ( !m_connection )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Asked to send message but do not have a valid connection!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_connection->get_state() != websocketpp::session::state::open )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Connection not yet open/upgraded, queueing work to send";
|
||||||
|
m_queuedMessagesToSend.append( bytes );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_connection->send( std::string( bytes.constData() ), websocketpp::frame::opcode::TEXT );
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod( this, "readOutput", Qt::QueuedConnection );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
onMessage( WebSocket* ws, websocketpp::connection_hdl, hatchet_client::message_ptr msg )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Handling message";
|
||||||
|
std::string payload = msg->get_payload();
|
||||||
|
ws->decodedMessage( QByteArray( payload.data(), payload.length() ) );
|
||||||
|
}
|
78
src/accounts/hatchet/sip/WebSocket.h
Normal file
78
src/accounts/hatchet/sip/WebSocket.h
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012, Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef WEBSOCKET__H
|
||||||
|
#define WEBSOCKET__H
|
||||||
|
|
||||||
|
#include "DllMacro.h"
|
||||||
|
|
||||||
|
#include "hatchet_config.hpp"
|
||||||
|
#include <websocketpp/client.hpp>
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QSslSocket>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
typedef typename websocketpp::client< websocketpp::config::hatchet_client > hatchet_client;
|
||||||
|
|
||||||
|
class WebSocket;
|
||||||
|
|
||||||
|
void onMessage( WebSocket* ws, websocketpp::connection_hdl, hatchet_client::message_ptr msg );
|
||||||
|
|
||||||
|
class DLLEXPORT WebSocket : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit WebSocket( const QString& url );
|
||||||
|
virtual ~WebSocket();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void connected();
|
||||||
|
void disconnected();
|
||||||
|
void decodedMessage( QByteArray bytes );
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setUrl( const QString& url );
|
||||||
|
void connectWs();
|
||||||
|
void disconnectWs();
|
||||||
|
void encodeMessage( const QByteArray& bytes );
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void socketStateChanged( QAbstractSocket::SocketState state );
|
||||||
|
void sslErrors( const QList< QSslError >& errors );
|
||||||
|
void encrypted();
|
||||||
|
void reconnectWs();
|
||||||
|
void readOutput();
|
||||||
|
void socketReadyRead();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY( WebSocket )
|
||||||
|
|
||||||
|
friend void onMessage( WebSocket *ws, websocketpp::connection_hdl, hatchet_client::message_ptr msg );
|
||||||
|
|
||||||
|
QUrl m_url;
|
||||||
|
std::stringstream m_outputStream;
|
||||||
|
std::unique_ptr< hatchet_client > m_client;
|
||||||
|
hatchet_client::connection_ptr m_connection;
|
||||||
|
QPointer< QSslSocket > m_socket;
|
||||||
|
QAbstractSocket::SocketState m_lastSocketState;
|
||||||
|
QList< QByteArray > m_queuedMessagesToSend;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
70
src/accounts/hatchet/sip/WebSocketThreadController.cpp
Normal file
70
src/accounts/hatchet/sip/WebSocketThreadController.cpp
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012, Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "WebSocketThreadController.h"
|
||||||
|
#include "WebSocket.h"
|
||||||
|
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
|
WebSocketThreadController::WebSocketThreadController( QObject* sip )
|
||||||
|
: QThread( nullptr )
|
||||||
|
, m_sip( sip )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WebSocketThreadController::~WebSocketThreadController()
|
||||||
|
{
|
||||||
|
if ( m_webSocket )
|
||||||
|
{
|
||||||
|
delete m_webSocket;
|
||||||
|
m_webSocket = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocketThreadController::setUrl( const QString &url )
|
||||||
|
{
|
||||||
|
m_url = url;
|
||||||
|
if ( m_webSocket )
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod( m_webSocket, "setUrl", Qt::QueuedConnection, Q_ARG( QString, url ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebSocketThreadController::run()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Starting";
|
||||||
|
m_webSocket = QPointer< WebSocket >( new WebSocket( m_url ) );
|
||||||
|
if ( m_webSocket && m_sip )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Have a valid websocket and parent";
|
||||||
|
connect( m_sip, SIGNAL( connectWebSocket() ), m_webSocket, SLOT( connectWs() ), Qt::QueuedConnection );
|
||||||
|
connect( m_sip, SIGNAL( disconnectWebSocket() ), m_webSocket, SLOT( disconnectWs() ), Qt::QueuedConnection );
|
||||||
|
connect( m_sip, SIGNAL( rawBytes( QByteArray ) ), m_webSocket, SLOT( encodeMessage( QByteArray ) ), Qt::QueuedConnection );
|
||||||
|
connect( m_webSocket, SIGNAL( connected() ), m_sip, SLOT( webSocketConnected() ), Qt::QueuedConnection );
|
||||||
|
connect( m_webSocket, SIGNAL( disconnected() ), m_sip, SLOT( webSocketDisconnected() ), Qt::QueuedConnection );
|
||||||
|
connect( m_webSocket, SIGNAL( decodedMessage( QByteArray ) ), m_sip, SLOT( messageReceived( QByteArray ) ), Qt::QueuedConnection );
|
||||||
|
QMetaObject::invokeMethod( m_webSocket, "connectWs", Qt::QueuedConnection );
|
||||||
|
exec();
|
||||||
|
delete m_webSocket;
|
||||||
|
m_webSocket = 0;
|
||||||
|
}
|
||||||
|
}
|
49
src/accounts/hatchet/sip/WebSocketThreadController.h
Normal file
49
src/accounts/hatchet/sip/WebSocketThreadController.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2012, Leo Franchi <lfranchi@kde.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef WEBSOCKET_THREAD_CONTROLLER_H
|
||||||
|
#define WEBSOCKET_THREAD_CONTROLLER_H
|
||||||
|
|
||||||
|
#include "DllMacro.h"
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
class WebSocket;
|
||||||
|
|
||||||
|
class DLLEXPORT WebSocketThreadController : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit WebSocketThreadController( QObject* sip );
|
||||||
|
virtual ~WebSocketThreadController();
|
||||||
|
|
||||||
|
void setUrl( const QString &url );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY( WebSocketThreadController )
|
||||||
|
|
||||||
|
QPointer< WebSocket > m_webSocket;
|
||||||
|
QPointer< QObject > m_sip;
|
||||||
|
QString m_url;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
72
src/accounts/hatchet/sip/hatchet_config.hpp
Normal file
72
src/accounts/hatchet/sip/hatchet_config.hpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||||
|
* Copyright (c) 2013, Jeff Mitchell <jeff@tomahawk-player.org>. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the WebSocket++ Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WEBSOCKETPP_CONFIG_HATCHET_CLIENT_HPP
|
||||||
|
#define WEBSOCKETPP_CONFIG_HATCHET_CLIENT_HPP
|
||||||
|
|
||||||
|
#include <websocketpp/config/core_client.hpp>
|
||||||
|
#include <websocketpp/transport/iostream/endpoint.hpp>
|
||||||
|
#include <websocketpp/concurrency/none.hpp>
|
||||||
|
|
||||||
|
namespace websocketpp {
|
||||||
|
namespace config {
|
||||||
|
|
||||||
|
struct hatchet_client : public core_client {
|
||||||
|
typedef hatchet_client type;
|
||||||
|
|
||||||
|
typedef websocketpp::concurrency::none concurrency_type;
|
||||||
|
|
||||||
|
typedef core_client::request_type request_type;
|
||||||
|
typedef core_client::response_type response_type;
|
||||||
|
|
||||||
|
typedef core_client::message_type message_type;
|
||||||
|
typedef core_client::con_msg_manager_type con_msg_manager_type;
|
||||||
|
typedef core_client::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||||
|
|
||||||
|
typedef core_client::alog_type alog_type;
|
||||||
|
typedef core_client::elog_type elog_type;
|
||||||
|
|
||||||
|
typedef core_client::rng_type rng_type;
|
||||||
|
|
||||||
|
struct transport_config {
|
||||||
|
typedef type::concurrency_type concurrency_type;
|
||||||
|
typedef type::alog_type alog_type;
|
||||||
|
typedef type::elog_type elog_type;
|
||||||
|
typedef type::request_type request_type;
|
||||||
|
typedef type::response_type response_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef websocketpp::transport::iostream::endpoint<transport_config> transport_type;
|
||||||
|
|
||||||
|
//static const websocketpp::log::level alog_level = websocketpp::log::alevel::all;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace config
|
||||||
|
} // namespace websocketpp
|
||||||
|
|
||||||
|
#endif // WEBSOCKETPP_CONFIG_HATCHET_CLIENT_HPP
|
@@ -54,7 +54,7 @@ Closure::Closure(QObject* sender,
|
|||||||
|
|
||||||
Closure::Closure(QObject* sender,
|
Closure::Closure(QObject* sender,
|
||||||
const char* signal,
|
const char* signal,
|
||||||
std::tr1::function<void()> callback)
|
function<void()> callback)
|
||||||
: callback_(callback) {
|
: callback_(callback) {
|
||||||
Connect(sender, signal);
|
Connect(sender, signal);
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,13 @@
|
|||||||
|
|
||||||
#include "DllMacro.h"
|
#include "DllMacro.h"
|
||||||
|
|
||||||
|
#ifdef _WEBSOCKETPP_CPP11_STL_
|
||||||
|
#include <functional>
|
||||||
|
using std::function;
|
||||||
|
#else
|
||||||
#include <tr1/functional>
|
#include <tr1/functional>
|
||||||
|
using std::tr1::function;
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <QMetaMethod>
|
#include <QMetaMethod>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
@@ -64,7 +70,7 @@ class DLLEXPORT Closure : public QObject, boost::noncopyable {
|
|||||||
const ClosureArgumentWrapper* val3 = 0);
|
const ClosureArgumentWrapper* val3 = 0);
|
||||||
|
|
||||||
Closure(QObject* sender, const char* signal,
|
Closure(QObject* sender, const char* signal,
|
||||||
std::tr1::function<void()> callback);
|
function<void()> callback);
|
||||||
|
|
||||||
void setAutoDelete( bool autoDelete ) { autoDelete_ = autoDelete; }
|
void setAutoDelete( bool autoDelete ) { autoDelete_ = autoDelete; }
|
||||||
|
|
||||||
@@ -87,7 +93,7 @@ class DLLEXPORT Closure : public QObject, boost::noncopyable {
|
|||||||
void Connect(QObject* sender, const char* signal);
|
void Connect(QObject* sender, const char* signal);
|
||||||
|
|
||||||
QMetaMethod slot_;
|
QMetaMethod slot_;
|
||||||
std::tr1::function<void()> callback_;
|
function<void()> callback_;
|
||||||
bool autoDelete_;
|
bool autoDelete_;
|
||||||
QObject* outOfThreadReceiver_;
|
QObject* outOfThreadReceiver_;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user