1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-03-23 09:19:41 +01:00

Refactor peer announcement and disable Twitter until it's ported

This commit is contained in:
Dominik Schmidt 2013-01-12 03:21:31 +01:00
parent 54d0f23a44
commit 07887a4ade
25 changed files with 933 additions and 592 deletions

View File

@ -27,7 +27,7 @@
#include "accounts/AccountManager.h"
#include "network/Servent.h"
#include "sip/SipHandler.h"
#include "sip/PeerInfo.h"
#include "utils/TomahawkUtilsGui.h"
#include "utils/Logger.h"
#include "infosystem/InfoSystem.h"
@ -109,10 +109,7 @@ DiagnosticsDialog::updateLogView()
connect( account, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account, SIGNAL( error( int, QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account->sipPlugin(), SIGNAL( peerOnline( QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account->sipPlugin(), SIGNAL( peerOffline( QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account->sipPlugin(), SIGNAL( sipInfoReceived( QString, SipInfo ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account->sipPlugin(), SIGNAL( softwareVersionReceived( QString, QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
connect( account->sipPlugin(), SIGNAL( peerOnline( Tomahawk::peerinfo_ptr ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
log.append( accountLog( account ) + "\n" );
}
@ -163,15 +160,16 @@ DiagnosticsDialog::accountLog( Tomahawk::Accounts::Account* account )
.arg( stateString )
);
foreach( const QString& peerId, account->sipPlugin()->peersOnline() )
foreach( const Tomahawk::peerinfo_ptr& peerInfo, account->sipPlugin()->peersOnline() )
{
QString versionString = SipHandler::instance()->versionString( peerId );
SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId );
QString peerId = peerInfo->id();
QString versionString = peerInfo->versionString();
SipInfo sipInfo = peerInfo->sipInfo();
if ( !sipInfo.isValid() )
{
accountInfo.append(
QString(" %1: %2 %3" /*"(%4)"*/ "\n")
.arg( peerId )
QString(" %1: %2 %3" /*"(%4)"*/)
.arg( peerInfo->id() )
.arg( "sipinfo invalid" )
.arg( versionString )
// .arg( connected ? "connected" : "not connected")
@ -180,7 +178,7 @@ DiagnosticsDialog::accountLog( Tomahawk::Accounts::Account* account )
else if ( sipInfo.isVisible() )
{
accountInfo.append(
QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n")
QString(" %1: %2:%3 %4" /*" (%5)"*/)
.arg( peerId )
.arg( sipInfo.host() )
.arg( sipInfo.port() )
@ -191,14 +189,29 @@ DiagnosticsDialog::accountLog( Tomahawk::Accounts::Account* account )
else
{
accountInfo.append(
QString(" %1: visible: false %2" /*" (%3)"*/ "\n")
QString(" %1: visible: false %2" /*" (%3)"*/)
.arg( peerId )
.arg( versionString )
// .arg( connected ? "connected" : "not connected")
);
}
if( sipInfo.isValid() )
{
if( !Servent::instance()->visibleExternally() ||
Servent::instance()->externalAddress() < sipInfo.host() ||
( Servent::instance()->externalAddress() == sipInfo.host() && Servent::instance()->externalPort() < sipInfo.port() ) )
{
accountInfo.append(" (outbound)");
}
else
{
accountInfo.append(" (inbound)");
}
}
accountInfo.append("\n");
}
accountInfo.append( "\n" );
return accountInfo;
}
}

View File

@ -4,8 +4,8 @@ IF( JREEN_FOUND )
add_subdirectory( xmpp )
ENDIF()
IF( QTWEETLIB_FOUND AND BUILD_GUI )
ADD_SUBDIRECTORY( twitter )
ENDIF()
# IF( QTWEETLIB_FOUND AND BUILD_GUI )
# ADD_SUBDIRECTORY( twitter )
# ENDIF()
#
ADD_SUBDIRECTORY( zeroconf )

View File

@ -30,6 +30,7 @@
#include "accounts/AccountManager.h"
#include "TomahawkSettings.h"
#include "utils/TomahawkUtilsGui.h"
#include "sip/PeerInfo.h"
#include "config.h"
#include "TomahawkVersion.h"
@ -432,9 +433,9 @@ XmppSipPlugin::errorMessage( Jreen::Client::DisconnectReason reason )
void
XmppSipPlugin::sendMsg( const QString& to, const SipInfo& info )
XmppSipPlugin::sendSipInfo( const Tomahawk::peerinfo_ptr& receiver, const SipInfo& info )
{
qDebug() << Q_FUNC_INFO << to << info;
qDebug() << Q_FUNC_INFO << receiver << info;
if ( !m_client )
return;
@ -447,8 +448,8 @@ XmppSipPlugin::sendMsg( const QString& to, const SipInfo& info )
else
sipMessage = new TomahawkXmppMessage();
qDebug() << "Send sip messsage to" << to;
Jreen::IQ iq( Jreen::IQ::Set, to );
qDebug() << "Send sip messsage to" << receiver;
Jreen::IQ iq( Jreen::IQ::Set, receiver->id() );
iq.addExtension( sipMessage );
Jreen::IQReply *reply = m_client->send( iq );
reply->setData( SipMessageSent );
@ -689,13 +690,10 @@ XmppSipPlugin::onNewMessage( const Jreen::Message& message )
// this is not a sip message, so we send it directly through the client
m_client->send( Jreen::Message ( Jreen::Message::Error, Jreen::JID( to ), response) );
emit msgReceived( from, msg );
return;
}
qDebug() << Q_FUNC_INFO << "From:" << message.from().full() << ":" << message.body();
emit sipInfoReceived( from, info );
}
@ -864,7 +862,11 @@ XmppSipPlugin::onNewIq( const Jreen::IQ& iq )
{
QString versionString = QString( "%1 %2 %3" ).arg( softwareVersion->name(), softwareVersion->os(), softwareVersion->version() );
qDebug() << Q_FUNC_INFO << "Received software version for" << iq.from().full() << ":" << versionString;
emit softwareVersionReceived( iq.from().full(), versionString );
Tomahawk::peerinfo_ptr peerInfo = PeerInfo::get( this, iq.from().full() );
if( !peerInfo.isNull() )
{
peerInfo->setVersionString( versionString );
}
}
}
else if ( context == RequestedDisco )
@ -902,7 +904,13 @@ XmppSipPlugin::onNewIq( const Jreen::IQ& iq )
Q_ASSERT( info.isValid() );
qDebug() << Q_FUNC_INFO << "From:" << iq.from().full() << ":" << info;
emit sipInfoReceived( iq.from().full(), info );
Tomahawk::peerinfo_ptr peerInfo = PeerInfo::get( this, iq.from().full() );
if( peerInfo.isNull() )
{
tDebug() << Q_FUNC_INFO << "no valid peerInfo for " << iq.from().full();
return;
}
peerInfo->setSipInfo( info );
}
}
}
@ -930,14 +938,23 @@ XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type pr
{
QString fulljid = jid.full();
if(fulljid.contains("public.talk.google.com"))
return;
// "going offline" event
if ( !presenceMeansOnline( presenceType ) &&
( !m_peers.contains( jid ) || presenceMeansOnline( m_peers.value( jid ) ) ) )
{
m_peers[ jid ] = presenceType;
qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid;
emit peerOffline( fulljid );
m_peers[ jid ] = presenceType;
Tomahawk::peerinfo_ptr peerInfo = PeerInfo::get( this, fulljid );
if( !peerInfo.isNull() )
{
peerInfo->setStatus( PeerInfo::Offline );
}
return;
}
@ -945,10 +962,12 @@ XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type pr
if ( presenceMeansOnline( presenceType ) &&
( !m_peers.contains( jid ) || !presenceMeansOnline( m_peers.value( jid ) ) ) )
{
m_peers[ jid ] = presenceType;
qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid;
emit peerOnline( fulljid );
m_peers[ jid ] = presenceType;
Tomahawk::peerinfo_ptr peerInfo = PeerInfo::get( this, fulljid, PeerInfo::AutoCreate );
peerInfo->setStatus( PeerInfo::Online );
#ifndef ENABLE_HEADLESS
if ( !m_avatarManager->avatar( jid.bare() ).isNull() )
@ -986,16 +1005,17 @@ XmppSipPlugin::onNewAvatar( const QString& jid )
{
if ( peer.bare() == jid )
{
emit avatarReceived( peer.full(), m_avatarManager->avatar( jid ) );
Tomahawk::peerinfo_ptr peerInfo = PeerInfo::get( this, peer.full() );
if( !peerInfo.isNull() )
peerInfo->setAvatar( m_avatarManager->avatar( jid ) );
}
}
if ( jid == m_client->jid().bare() )
{
// own avatar
emit avatarReceived( m_avatarManager->avatar( jid ) );
else
// someone else's avatar
emit avatarReceived( jid, m_avatarManager->avatar( jid ) );
}
#endif
}

View File

@ -88,9 +88,10 @@ public slots:
virtual void disconnectPlugin();
virtual void checkSettings();
virtual void configurationChanged();
virtual void sendMsg( const QString& peerId, const SipInfo& info );
virtual void addContact( const QString& peerId, const QString& msg = QString() );
virtual void sendSipInfo( const Tomahawk::peerinfo_ptr& receiver, const SipInfo& info );
void showAddFriendDialog();
void publishTune( const QUrl& url, const Tomahawk::InfoSystem::InfoStringHash& trackInfo );

View File

@ -23,6 +23,8 @@
#include "utils/Logger.h"
#include "ZeroconfAccount.h"
#include "Source.h"
#include "sip/PeerInfo.h"
#include "network/ControlConnection.h"
#include <QtPlugin>
#include <QTimer>
@ -56,6 +58,12 @@ ZeroconfPlugin::accountName() const
return QString( MYNAME );
}
const QString
ZeroconfPlugin::serviceName() const
{
return QString( MYNAME );
}
const QString
ZeroconfPlugin::friendlyName() const
{
@ -82,8 +90,7 @@ ZeroconfPlugin::connectPlugin()
foreach( const QStringList& nodeSet, m_cachedNodes )
{
if ( !Servent::instance()->connectedToSession( nodeSet[3] ) )
Servent::instance()->connectToPeer( nodeSet[0], nodeSet[1].toInt(), "whitelist", nodeSet[2], nodeSet[3] );
lanHostFound( nodeSet[0], nodeSet[1].toInt(), nodeSet[2], nodeSet[3]);
}
m_cachedNodes.clear();
@ -135,9 +142,18 @@ ZeroconfPlugin::lanHostFound( const QString& host, int port, const QString& name
return;
}
if ( !Servent::instance()->connectedToSession( nodeid ) )
Servent::instance()->connectToPeer( host, port, "whitelist", name, nodeid );
else
qDebug() << "Already connected to" << host;
SipInfo sipInfo;
sipInfo.setHost( host );
sipInfo.setPort( port );
sipInfo.setUniqname( nodeid );
sipInfo.setKey( "whitelist" );
sipInfo.setVisible( true );
Tomahawk::peerinfo_ptr peerInfo = Tomahawk::PeerInfo::get( this, host, Tomahawk::PeerInfo::AutoCreate );
peerInfo->setSipInfo( sipInfo );
peerInfo->setFriendlyName( name );
peerInfo->setType( PeerInfo::Local );
peerInfo->setStatus( PeerInfo::Online );
}

View File

@ -28,7 +28,7 @@
#include <QtCore/QTimer>
#define MYNAME "Local Network"
#define MYNAME "zeroconf"
namespace Tomahawk
{
@ -50,6 +50,7 @@ public:
virtual const QString name() const;
virtual const QString friendlyName() const;
virtual const QString accountName() const;
virtual const QString serviceName() const;
virtual Account::ConnectionState connectionState() const;
virtual bool isValid() const { return true; }
#ifndef ENABLE_HEADLESS
@ -64,7 +65,7 @@ public slots:
void advertise();
void sendMsg( const QString&, const SipInfo& ) {}
void sendSipInfo( const Tomahawk::peerinfo_ptr&, const SipInfo& ) {}
void broadcastMsg( const QString & ) {}
void addContact( const QString &, const QString& ) {}

View File

@ -212,8 +212,8 @@ list(APPEND libSources
accounts/lastfm/LastFmInfoPlugin.cpp
sip/SipPlugin.cpp
sip/SipHandler.cpp
sip/SipInfo.cpp
sip/PeerInfo.cpp
audio/AudioEngine.cpp

View File

@ -32,7 +32,6 @@
#include "database/Database.h"
#include <QCoreApplication>
#include <QBuffer>
#include "utils/TomahawkCache.h"
#include "database/DatabaseCommand_SocialAction.h"
@ -42,6 +41,7 @@
#endif
#include "utils/Logger.h"
#include "sip/PeerInfo.h"
using namespace Tomahawk;
@ -53,12 +53,9 @@ Source::Source( int id, const QString& username )
, m_username( username )
, m_id( id )
, m_updateIndexWhenSynced( false )
, m_avatarUpdated( true )
, m_state( DBSyncConnection::UNKNOWN )
, m_cc( 0 )
, m_commandCount( 0 )
, m_avatar( 0 )
, m_fancyAvatar( 0 )
{
m_scrubFriendlyName = qApp->arguments().contains( "--demo" );
@ -79,8 +76,6 @@ Source::Source( int id, const QString& username )
Source::~Source()
{
qDebug() << Q_FUNC_INFO << friendlyName();
delete m_avatar;
delete m_fancyAvatar;
}
@ -129,80 +124,27 @@ Source::friendlyName() const
#ifndef ENABLE_HEADLESS
void
Source::setAvatar( const QPixmap& avatar )
{
QByteArray ba;
QBuffer buffer( &ba );
buffer.open( QIODevice::WriteOnly );
avatar.save( &buffer, "PNG" );
// Check if the avatar is different by comparing a hash of the first 4096 bytes
const QByteArray hash = QCryptographicHash::hash( ba.left( 4096 ), QCryptographicHash::Sha1 );
if ( m_avatarHash == hash )
return;
else
m_avatarHash = hash;
delete m_avatar;
m_avatar = new QPixmap( avatar );
m_fancyAvatar = 0;
TomahawkUtils::Cache::instance()->putData( "Sources", 7776000000 /* 90 days */, m_username, ba );
m_avatarUpdated = true;
}
QPixmap
Source::avatar( TomahawkUtils::ImageMode style, const QSize& size )
{
if ( !m_avatar && m_avatarUpdated )
if( controlConnection() )
{
m_avatar = new QPixmap();
QByteArray ba = TomahawkUtils::Cache::instance()->getData( "Sources", m_username ).toByteArray();
if ( ba.count() )
m_avatar->loadFromData( ba );
if ( m_avatar->isNull() )
// tLog() << "****************************************************************************************";
// tLog() << controlConnection()->peerInfos().count() << "PEERS FOR " << friendlyName();
QPixmap result;
foreach( const peerinfo_ptr& peerInfo, controlConnection()->peerInfos() )
{
delete m_avatar;
m_avatar = 0;
// peerInfoDebug(peerInfo);
if( !peerInfo.isNull() && !peerInfo->avatar( style, size ).isNull() )
{
result = peerInfo->avatar( style, size );
}
}
m_avatarUpdated = false;
// tLog() << "****************************************************************************************";
return result;
}
if ( style == TomahawkUtils::RoundedCorners && m_avatar && !m_avatar->isNull() && !m_fancyAvatar )
m_fancyAvatar = new QPixmap( TomahawkUtils::createRoundedImage( QPixmap( *m_avatar ), QSize( 0, 0 ) ) );
QPixmap pixmap;
if ( style == TomahawkUtils::RoundedCorners && m_fancyAvatar )
{
pixmap = *m_fancyAvatar;
}
else if ( m_avatar )
{
pixmap = *m_avatar;
}
if ( !pixmap.isNull() && !size.isEmpty() )
{
if ( m_coverCache[ style ].contains( size.width() ) )
{
return m_coverCache[ style ].value( size.width() );
}
QPixmap scaledCover;
scaledCover = pixmap.scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
QHash< int, QPixmap > innerCache = m_coverCache[ style ];
innerCache.insert( size.width(), scaledCover );
m_coverCache[ style ] = innerCache;
return scaledCover;
}
return pixmap;
return QPixmap();
}
#endif

View File

@ -66,7 +66,6 @@ public:
void setFriendlyName( const QString& fname );
#ifndef ENABLE_HEADLESS
void setAvatar( const QPixmap& avatar );
QPixmap avatar( TomahawkUtils::ImageMode style = TomahawkUtils::Original, const QSize& size = QSize() );
#endif
@ -147,7 +146,6 @@ private:
int m_id;
bool m_scrubFriendlyName;
bool m_updateIndexWhenSynced;
bool m_avatarUpdated;
Tomahawk::query_ptr m_currentTrack;
QString m_textStatus;
@ -160,11 +158,6 @@ private:
QString m_lastCmdGuid;
mutable QMutex m_cmdMutex;
mutable QPixmap* m_avatar;
mutable QPixmap* m_fancyAvatar;
mutable QByteArray m_avatarHash;
mutable QHash< TomahawkUtils::ImageMode, QHash< int, QPixmap > > m_coverCache;
Tomahawk::playlistinterface_ptr m_playlistInterface;
};

View File

@ -23,7 +23,6 @@
#include <QDir>
#include "Source.h"
#include "sip/SipHandler.h"
#include "PlaylistInterface.h"
#include "utils/Logger.h"

View File

@ -46,6 +46,7 @@ namespace Tomahawk
class Source;
class DynamicControl;
class GeneratorInterface;
class PeerInfo;
typedef QSharedPointer<Collection> collection_ptr;
typedef QSharedPointer<Playlist> playlist_ptr;
@ -57,6 +58,7 @@ namespace Tomahawk
typedef QSharedPointer<Source> source_ptr;
typedef QSharedPointer<Artist> artist_ptr;
typedef QSharedPointer<Album> album_ptr;
typedef QSharedPointer<PeerInfo> peerinfo_ptr;
typedef QSharedPointer<DynamicControl> dyncontrol_ptr;
typedef QSharedPointer<GeneratorInterface> geninterface_ptr;

View File

@ -28,7 +28,6 @@
#include <QtCore/QPluginLoader>
#include <QtCore/QCoreApplication>
#include <QTimer>
#include <sip/SipHandler.h>
namespace Tomahawk
{
@ -58,8 +57,6 @@ AccountManager::AccountManager( QObject *parent )
AccountManager::~AccountManager()
{
delete SipHandler::instance();
disconnectAll();
qDeleteAll( m_accounts );
qDeleteAll( m_accountFactories );
@ -397,6 +394,18 @@ AccountManager::addAccountFactory( AccountFactory* factory )
}
Account*
AccountManager::zeroconfAccount() const
{
foreach( Account* account, accounts() )
{
if( account->sipPlugin() && account->sipPlugin()->serviceName() == "zeroconf" )
return account;
}
return 0;
}
void
AccountManager::hookupAccount( Account* account ) const
{
@ -411,9 +420,6 @@ AccountManager::hookupAndEnable( Account* account, bool startup )
Q_UNUSED( startup );
tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
SipPlugin* p = account->sipPlugin();
if ( p )
SipHandler::instance()->hookUpPlugin( p );
hookupAccount( account );
if ( account->enabled() )

View File

@ -80,6 +80,8 @@ public:
void addAccountFactory( AccountFactory* factory );
Account* zeroconfAccount() const;
public slots:
void connectAll();
void disconnectAll();

View File

@ -26,7 +26,7 @@
#include "SourceList.h"
#include "network/DbSyncConnection.h"
#include "network/Servent.h"
#include "sip/SipHandler.h"
#include "sip/PeerInfo.h"
#include "utils/Logger.h"
#define TCP_TIMEOUT 600
@ -34,7 +34,7 @@
using namespace Tomahawk;
ControlConnection::ControlConnection( Servent* parent, const QHostAddress &ha )
ControlConnection::ControlConnection( Servent* parent )
: Connection( parent )
, m_dbsyncconn( 0 )
, m_registered( false )
@ -48,38 +48,6 @@ ControlConnection::ControlConnection( Servent* parent, const QHostAddress &ha )
this->setMsgProcessorModeIn( MsgProcessor::UNCOMPRESS_ALL | MsgProcessor::PARSE_JSON );
this->setMsgProcessorModeOut( MsgProcessor::COMPRESS_IF_LARGE );
m_peerIpAddress = ha;
}
ControlConnection::ControlConnection( Servent* parent, const QString &ha )
: Connection( parent )
, m_dbsyncconn( 0 )
, m_registered( false )
, m_pingtimer( 0 )
{
qDebug() << "CTOR controlconnection";
setId("ControlConnection()");
// auto delete when connection closes:
connect( this, SIGNAL( finished() ), SLOT( deleteLater() ) );
this->setMsgProcessorModeIn( MsgProcessor::UNCOMPRESS_ALL | MsgProcessor::PARSE_JSON );
this->setMsgProcessorModeOut( MsgProcessor::COMPRESS_IF_LARGE );
if ( !ha.isEmpty() )
{
QHostAddress qha( ha );
if ( !qha.isNull() )
m_peerIpAddress = qha;
else
{
QHostInfo qhi = QHostInfo::fromName( ha );
if ( !qhi.addresses().isEmpty() )
m_peerIpAddress = qhi.addresses().first();
}
}
}
@ -107,7 +75,7 @@ ControlConnection::source() const
Connection*
ControlConnection::clone()
{
ControlConnection* clone = new ControlConnection( servent(), m_peerIpAddress.toString() );
ControlConnection* clone = new ControlConnection( servent() );
clone->setOnceOnly( onceOnly() );
clone->setName( name() );
return clone;
@ -158,16 +126,7 @@ ControlConnection::registerSource()
Q_UNUSED( source )
Q_ASSERT( source == m_source.data() );
#ifndef ENABLE_HEADLESS
// qDebug() << Q_FUNC_INFO << "Setting avatar ... " << name() << !SipHandler::instance()->avatar( name() ).isNull();
if ( !SipHandler::instance()->avatar( name() ).isNull() )
{
source->setAvatar( SipHandler::instance()->avatar( name() ) );
}
#endif
m_registered = true;
m_servent->registerControlConnection( this );
setupDbSyncConnection();
}
@ -311,3 +270,18 @@ ControlConnection::onPingTimer()
sendMsg( Msg::factory( QByteArray(), Msg::PING ) );
}
void
ControlConnection::addPeerInfo( const peerinfo_ptr& peerInfo )
{
peerInfo->setControlConnection( this );
m_peerInfos.insert( peerInfo );
}
const QSet< peerinfo_ptr >
ControlConnection::peerInfos() const
{
return m_peerInfos;
}

View File

@ -40,8 +40,7 @@ class DLLEXPORT ControlConnection : public Connection
Q_OBJECT
public:
explicit ControlConnection( Servent* parent = 0, const QHostAddress &ha = QHostAddress() );
explicit ControlConnection( Servent* parent = 0, const QString &ha = QString() );
ControlConnection( Servent* parent );
~ControlConnection();
Connection* clone();
@ -49,6 +48,9 @@ public:
Tomahawk::source_ptr source() const;
void addPeerInfo( const Tomahawk::peerinfo_ptr& peerInfo );
const QSet< Tomahawk::peerinfo_ptr > peerInfos() const;
protected:
virtual void setup();
@ -71,6 +73,8 @@ private:
QTimer* m_pingtimer;
QTime m_pingtimer_mark;
QSet< Tomahawk::peerinfo_ptr > m_peerInfos;
};
#endif // CONTROLCONNECTION_H

View File

@ -19,6 +19,25 @@
#include "Servent.h"
#include "Result.h"
#include "Source.h"
#include "BufferIoDevice.h"
#include "Connection.h"
#include "ControlConnection.h"
#include "database/Database.h"
#include "database/DatabaseImpl.h"
#include "StreamConnection.h"
#include "SourceList.h"
#include "sip/SipInfo.h"
#include "sip/PeerInfo.h"
#include "sip/SipPlugin.h"
#include "PortFwdThread.h"
#include "TomahawkSettings.h"
#include "utils/TomahawkUtils.h"
#include "utils/Logger.h"
#include "accounts/AccountManager.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QMutexLocker>
#include <QtNetwork/QNetworkInterface>
@ -30,21 +49,6 @@
#include <boost/bind.hpp>
#include "Result.h"
#include "Source.h"
#include "BufferIoDevice.h"
#include "Connection.h"
#include "ControlConnection.h"
#include "database/Database.h"
#include "database/DatabaseImpl.h"
#include "StreamConnection.h"
#include "SourceList.h"
#include "PortFwdThread.h"
#include "TomahawkSettings.h"
#include "utils/TomahawkUtils.h"
#include "utils/Logger.h"
using namespace Tomahawk;
Servent* Servent::s_instance = 0;
@ -168,7 +172,7 @@ Servent::createConnectionKey( const QString& name, const QString &nodeid, const
Q_ASSERT( this->thread() == QThread::currentThread() );
QString _key = ( key.isEmpty() ? uuid() : key );
ControlConnection* cc = new ControlConnection( this, name );
ControlConnection* cc = new ControlConnection( this );
cc->setName( name.isEmpty() ? QString( "KEY(%1)" ).arg( key ) : name );
if ( !nodeid.isEmpty() )
cc->setId( nodeid );
@ -268,16 +272,142 @@ Servent::unregisterControlConnection( ControlConnection* conn )
ControlConnection*
Servent::lookupControlConnection( const QString& name )
Servent::lookupControlConnection( const SipInfo& sipInfo )
{
foreach( ControlConnection* c, m_controlconnections )
if( c->name() == name )
return c;
{
tLog() << sipInfo.port() << c->peerPort() << sipInfo.host() << c->peerIpAddress().toString();
if ( sipInfo.port() == c->peerPort() && sipInfo.host() == c->peerIpAddress().toString() )
return c;
}
return NULL;
}
void
Servent::registerPeer( const Tomahawk::peerinfo_ptr& peerInfo )
{
if( peerInfo->hasControlConnection() )
{
peerInfoDebug(peerInfo) << "already had control connection, not doin nuffin: " << peerInfo->controlConnection()->name();
tLog() << "existing control connection has following peers:";
foreach(const peerinfo_ptr& otherPeerInfo, peerInfo->controlConnection()->peerInfos())
{
peerInfoDebug(otherPeerInfo);
}
tLog() << "end peers";
return;
}
if( peerInfo->type() == Tomahawk::PeerInfo::Local )
{
peerInfoDebug(peerInfo) << "YAY, we need to establish the connection now.. thinking";
if ( !connectedToSession( peerInfo->sipInfo().uniqname() ) )
{
Servent::instance()->connectToPeer( peerInfo );
}
else
{
// FIXME: do we need to port this?!
// qDebug() << "Already connected to" << host; // so peerInfo was 0 before
// qDebug() << "They connected to us and we don't have a PeerInfo object, created one...";
// m_peersOnline.append( peerInfo );
// // attach to control connection
// ControlConnection* conn = Servent::instance()->lookupControlConnection( sipInfo );
// // we're connected to this nodeid, so we should find a control connection for this sipinfo, no?
// Q_ASSERT( conn );
// conn->addPeerInfo( peerInfo );
}
}
else
{
SipInfo info;
if( Servent::instance()->visibleExternally() )
{
QString peerId = peerInfo->id();
QString key = uuid();
ControlConnection* conn = new ControlConnection( Servent::instance() );
const QString& nodeid = Database::instance()->impl()->dbid();
conn->setName( peerId.left( peerId.indexOf( "/" ) ) );
conn->setId( nodeid );
conn->addPeerInfo( peerInfo );
Servent::instance()->registerOffer( key, conn );
info.setVisible( true );
info.setHost( Servent::instance()->externalAddress() );
info.setPort( Servent::instance()->externalPort() );
info.setKey( key );
info.setUniqname( nodeid );
tDebug() << "Asking them ( " << peerInfo->id() << " ) to connect to us:" << info;
}
else
{
info.setVisible( false );
tDebug() << "We are not visible externally:" << info;
}
peerInfo->sendLocalSipInfo( info );
handleSipInfo( peerInfo );
connect( peerInfo.data(), SIGNAL( sipInfoChanged() ), SLOT( onSipInfoChanged() ) );
}
}
void
Servent::onSipInfoChanged()
{
Tomahawk::PeerInfo* peerInfo = qobject_cast< Tomahawk::PeerInfo* >( sender() );
if( !peerInfo )
return;
handleSipInfo( peerInfo->weakRef().toStrongRef() );
}
void Servent::handleSipInfo( const Tomahawk::peerinfo_ptr& peerInfo )
{
tLog() << Q_FUNC_INFO << peerInfo->id() << peerInfo->sipInfo();
SipInfo info = peerInfo->sipInfo();
if( !info.isValid() )
return;
/*
If only one party is externally visible, connection is obvious
If both are, peer with lowest IP address initiates the connection.
This avoids dupe connections.
*/
if ( info.isVisible() )
{
if( !Servent::instance()->visibleExternally() ||
Servent::instance()->externalAddress() < info.host() ||
( Servent::instance()->externalAddress() == info.host() && Servent::instance()->externalPort() < info.port() ) )
{
tDebug() << "Initiate connection to" << peerInfo->id() << "at" << info.host() << " peer of: " << peerInfo->sipPlugin()->account()->accountFriendlyName();
Servent::instance()->connectToPeer( peerInfo );
}
else
{
tDebug() << Q_FUNC_INFO << "They should be conecting to us...";
}
}
else
{
tDebug() << Q_FUNC_INFO << "They are not visible, doing nothing atm";
}
}
void
Servent::incomingConnection( int sd )
{
@ -344,16 +474,21 @@ Servent::readyRead()
controlid = m.value( "controlid" ).toString();
tDebug( LOGVERBOSE ) << "Incoming connection details:" << m;
if( !nodeid.isEmpty() ) // only control connections send nodeid
{
bool dupe = false;
if ( m_connectedNodes.contains( nodeid ) )
{
tDebug() << "connected nodes contains it.";
dupe = true;
}
foreach( ControlConnection* con, m_controlconnections )
{
tLog( LOGVERBOSE ) << "known connection:" << con->id() << con->source()->friendlyName();
if(!con)
continue;
tLog() << "known connection:" << con->id();
if( con->id() == nodeid )
{
dupe = true;
@ -361,16 +496,47 @@ Servent::readyRead()
}
}
if ( dupe )
// for zeroconf there might be no offer, that case is handled later
ControlConnection* ccMatch = qobject_cast< ControlConnection* >( m_offers.value( key ).data() );
if ( dupe && ccMatch )
{
tLog() << "Duplicate control connection detected, dropping:" << nodeid << conntype;
tDebug() << "PEERINFO: to be dropped connection has following peers";
foreach(const peerinfo_ptr& currentPeerInfo, ccMatch->peerInfos() )
{
peerInfoDebug(currentPeerInfo);
}
foreach(ControlConnection* keepConnection, m_controlconnections)
{
Q_ASSERT(keepConnection);
if( !keepConnection )
continue;
if( keepConnection->id() == nodeid )
{
tDebug() << "Keep connection" << keepConnection->name() << "with following peers";
foreach( const peerinfo_ptr& currentPeerInfo, keepConnection->peerInfos() )
peerInfoDebug(currentPeerInfo);
tDebug() << "Add these peers now";
foreach( const peerinfo_ptr& currentPeerInfo, ccMatch->peerInfos() )
{
tDebug() << "Adding " << currentPeerInfo->id();
keepConnection->addPeerInfo( currentPeerInfo );
}
tDebug() << "Done adding.";
}
}
goto closeconnection;
}
}
foreach( ControlConnection* con, m_controlconnections )
{
if ( con->id() == controlid )
if ( con && con->id() == controlid )
{
cc = con;
break;
@ -398,7 +564,9 @@ Servent::readyRead()
tLog() << "Socket has become invalid, possibly took too long to make an ACL decision, key:" << key << nodeid;
goto closeconnection;
}
tDebug( LOGVERBOSE ) << "claimOffer OK:" << key << nodeid;
tDebug( LOGVERBOSE ) << "claimOffer OK:" << key << nodeid;
registerControlConnection( qobject_cast<ControlConnection*>(conn) );
m_connectedNodes << nodeid;
if( !nodeid.isEmpty() )
@ -526,26 +694,84 @@ Servent::socketError( QAbstractSocket::SocketError e )
void
Servent::connectToPeer( const QString& ha, int port, const QString &key, const QString& name, const QString& id )
Servent::connectToPeer( const peerinfo_ptr& peerInfo )
{
Q_ASSERT( this->thread() == QThread::currentThread() );
ControlConnection* conn = new ControlConnection( this, ha );
SipInfo sipInfo = peerInfo->sipInfo();
peerInfoDebug(peerInfo) << "connectToPeer: search for already established connections to the same nodeid: " << m_controlconnections.count() << "connections";
bool isDupe = false;
ControlConnection* conn = 0;
// try to find a ControlConnection with the same SipInfo, then we dont need to try to connect again
foreach( ControlConnection* c, m_controlconnections )
{
if( !c )
continue;
if( c->id() == sipInfo.uniqname() )
{
conn = c;
foreach(const peerinfo_ptr& currentPeerInfo, c->peerInfos())
{
tLog() << "peerInfo:" << currentPeerInfo->debugName() << "same object: " << (peerInfo == currentPeerInfo) << (peerInfo.data() == currentPeerInfo.data()) << (peerInfo->debugName() == currentPeerInfo->debugName());
if(peerInfo == currentPeerInfo)
{
isDupe = true;
tLog() << "Not adding " << peerInfo->debugName() << ", because it's a dupe: peerInfoCount remains " << conn->peerInfos().count();
}
}
if( !c->peerInfos().contains( peerInfo ) )
{
c->addPeerInfo( peerInfo );
// peerInfoDebug(peerInfo) << "Adding " << peerInfo->debugName() << ", not a dupe... new peerInfoCount:" << c->peerInfos().count();
// foreach(const peerinfo_ptr& kuh, c->peerInfos())
// {
// peerInfoDebug(peerInfo) << " ** " << kuh->debugName();
// }
}
break;
}
}
peerInfoDebug(peerInfo) << "connectToPeer: found a match: " << ( conn ? conn->name() : "false" ) << "dupe: " << isDupe;
if(isDupe)
{
peerInfoDebug(peerInfo) << "it's a dupe, nothing to do here, returning and stopping processing: peerInfoCount:" << conn->peerInfos().count();
}
if(conn)
return;
QVariantMap m;
m["conntype"] = "accept-offer";
m["key"] = key;
m["key"] = sipInfo.key();
m["port"] = externalPort();
m["nodeid"] = Database::instance()->impl()->dbid();
peerInfoDebug(peerInfo) << "No match found, creating a new ControlConnection...";
conn = new ControlConnection( this );
conn->addPeerInfo( peerInfo );
conn->setFirstMessage( m );
if( name.length() )
conn->setName( name );
if( id.length() )
conn->setId( id );
conn->setProperty( "nodeid", id );
if( peerInfo->id().length() )
conn->setName( peerInfo->id() );
connectToPeer( ha, port, key, conn );
if( sipInfo.uniqname().length() )
conn->setId( sipInfo.uniqname() );
conn->setProperty( "nodeid", sipInfo.uniqname() );
registerControlConnection( conn );
connectToPeer( sipInfo.host(), sipInfo.port(), sipInfo.key(), conn );
}
@ -654,8 +880,19 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
if( isIPWhitelisted( peer ) )
{
tDebug() << "Connection is from whitelisted IP range (LAN)";
Connection* conn = new ControlConnection( this, peer.toString() );
ControlConnection* conn = new ControlConnection( this );
conn->setName( peer.toString() );
Tomahawk::Accounts::Account* account = Tomahawk::Accounts::AccountManager::instance()->zeroconfAccount();
// if we get this connection the account should exist and be enabled
Q_ASSERT( account );
Q_ASSERT( account->enabled() );
// this is terrible, actually there should be a way to let this be created by the zeroconf plugin
// because this way we rely on the ip being used as id in two totally different parts of the code
Tomahawk::peerinfo_ptr peerInfo = Tomahawk::PeerInfo::get( account->sipPlugin(), peer.toString(), Tomahawk::PeerInfo::AutoCreate );
peerInfoDebug(peerInfo);
conn->addPeerInfo(peerInfo);
return conn;
}
else
@ -698,7 +935,7 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
else if ( noauth )
{
Connection* conn;
conn = new ControlConnection( this, peer );
conn = new ControlConnection( this );
conn->setName( key );
return conn;
}
@ -803,6 +1040,10 @@ Servent::connectedToSession( const QString& session )
{
foreach( ControlConnection* cc, m_controlconnections )
{
Q_ASSERT( cc );
if( !cc )
continue;
if( cc->id() == session )
return true;
}

View File

@ -51,6 +51,8 @@ class StreamConnection;
class ProxyConnection;
class RemoteCollectionConnection;
class PortFwdThread;
class PeerInfo;
class SipInfo;
// this is used to hold a bit of state, so when a connected signal is emitted
// from a socket, we can associate it with a Connection object etc.
@ -101,9 +103,17 @@ public:
void registerControlConnection( ControlConnection* conn );
void unregisterControlConnection( ControlConnection* conn );
ControlConnection* lookupControlConnection( const QString& name );
ControlConnection* lookupControlConnection( const SipInfo& sipInfo );
void connectToPeer( const QString& ha, int port, const QString &key, const QString& name = "", const QString& id = "" );
// you may call this method as often as you like for the same peerInfo, dupe checking is done inside
void registerPeer( const Tomahawk::peerinfo_ptr& peerInfo );
void handleSipInfo( const Tomahawk::peerinfo_ptr& peerInfo );
public slots:
void onSipInfoChanged();
public:
void connectToPeer( const Tomahawk::peerinfo_ptr& ha );
void connectToPeer( const QString& ha, int port, const QString &key, Connection* conn );
void reverseOfferRequest( ControlConnection* orig_conn, const QString &theirdbid, const QString& key, const QString& theirkey );

View File

@ -0,0 +1,315 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012, Dominik Schmidt <dev@dominik-schmidt.de>
*
* 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 "PeerInfo.h"
#include "SipPlugin.h"
#include "utils/TomahawkCache.h"
#include "utils/TomahawkUtilsGui.h"
#include "network/ControlConnection.h"
#include "network/Servent.h"
#include <QCryptographicHash>
#include <QBuffer>
namespace Tomahawk
{
QHash< QString, peerinfo_ptr > PeerInfo::s_peersByCacheKey = QHash< QString, peerinfo_ptr >();
inline QString
peerCacheKey( SipPlugin* plugin, const QString& peerId )
{
return QString( "%1\t\t%2" ).arg( (quintptr) plugin ).arg( peerId );
}
Tomahawk::peerinfo_ptr
PeerInfo::get(SipPlugin* parent, const QString& id, GetOptions options )
{
const QString key = peerCacheKey( parent, id );
if ( s_peersByCacheKey.contains( key ) )
{
return s_peersByCacheKey.value( key );
}
// if AutoCreate isn't enabled nothing to do here
if( ! ( options & AutoCreate ) )
{
return peerinfo_ptr();
}
peerinfo_ptr peerInfo( new PeerInfo( parent, id ) );
peerInfo->setWeakRef( peerInfo.toWeakRef() );
s_peersByCacheKey.insert( key, peerInfo);
return peerInfo;
}
QList< Tomahawk::peerinfo_ptr >
PeerInfo::getAll()
{
return s_peersByCacheKey.values();
}
PeerInfo::PeerInfo( SipPlugin* parent, const QString& id )
: QObject( parent )
, m_type( External )
, m_avatar( 0 )
, m_fancyAvatar( 0 )
, m_avatarUpdated( true )
{
m_id = id;
}
PeerInfo::~PeerInfo()
{
tDebug() << Q_FUNC_INFO;
delete m_avatar;
delete m_fancyAvatar;
}
void
PeerInfo::announce()
{
Servent::instance()->registerPeer( weakRef().toStrongRef() );
}
QWeakPointer< PeerInfo >
PeerInfo::weakRef()
{
return m_ownRef;
}
void
PeerInfo::setWeakRef( QWeakPointer< PeerInfo > weakRef )
{
m_ownRef = weakRef;
}
void
PeerInfo::setControlConnection( ControlConnection* controlConnection )
{
m_controlConnection = controlConnection;
}
ControlConnection*
PeerInfo::controlConnection() const
{
return m_controlConnection;
}
bool PeerInfo::hasControlConnection()
{
return !m_controlConnection.isNull();
}
void
PeerInfo::setType( Tomahawk::PeerInfo::Type type )
{
m_type = type;
}
PeerInfo::Type
PeerInfo::type() const
{
return m_type;
}
const
QString PeerInfo::id() const
{
return m_id;
}
SipPlugin*
PeerInfo::sipPlugin() const
{
return qobject_cast< SipPlugin* >( parent() );
}
void
PeerInfo::sendLocalSipInfo( const SipInfo& sipInfo )
{
sipPlugin()->sendSipInfo( weakRef().toStrongRef(), sipInfo );
}
const QString
PeerInfo::debugName() const
{
return QString("%1 : %2").arg( sipPlugin()->account()->accountFriendlyName() ).arg( id() );
}
void
PeerInfo::setStatus( PeerInfo::Status status )
{
m_status = status;
if( status == Online )
announce();
}
PeerInfo::Status
PeerInfo::status() const
{
return m_status;
}
void
PeerInfo::setSipInfo( const SipInfo& sipInfo )
{
if(sipInfo == m_sipInfo)
return;
m_sipInfo = sipInfo;
tLog() << "id: " << id() << " info changed" << sipInfo;
emit sipInfoChanged();
}
const SipInfo
PeerInfo::sipInfo() const
{
return m_sipInfo;
}
void
PeerInfo::setFriendlyName( const QString& friendlyName )
{
m_friendlyName = friendlyName;
}
const QString
PeerInfo::friendlyName() const
{
return m_friendlyName;
}
void
PeerInfo::setAvatar( const QPixmap& avatar )
{
QByteArray ba;
QBuffer buffer( &ba );
buffer.open( QIODevice::WriteOnly );
avatar.save( &buffer, "PNG" );
// Check if the avatar is different by comparing a hash of the first 4096 bytes
const QByteArray hash = QCryptographicHash::hash( ba.left( 4096 ), QCryptographicHash::Sha1 );
if ( m_avatarHash == hash )
return;
else
m_avatarHash = hash;
delete m_avatar;
m_avatar = new QPixmap( avatar );
m_fancyAvatar = 0;
TomahawkUtils::Cache::instance()->putData( "Sources", 7776000000 /* 90 days */, id(), ba );
m_avatarUpdated = true;
}
const QPixmap
PeerInfo::avatar( TomahawkUtils::ImageMode style, const QSize& size ) const
{
// tLog() << "*****************************************" << Q_FUNC_INFO << id();
if ( !m_avatar && m_avatarUpdated )
{
m_avatar = new QPixmap();
QByteArray ba = TomahawkUtils::Cache::instance()->getData( "Sources", id() ).toByteArray();
if ( ba.count() )
m_avatar->loadFromData( ba );
if ( m_avatar->isNull() )
{
delete m_avatar;
m_avatar = 0;
}
m_avatarUpdated = false;
}
if ( style == TomahawkUtils::RoundedCorners && m_avatar && !m_avatar->isNull() && !m_fancyAvatar )
m_fancyAvatar = new QPixmap( TomahawkUtils::createRoundedImage( QPixmap( *m_avatar ), QSize( 0, 0 ) ) );
QPixmap pixmap;
if ( style == TomahawkUtils::RoundedCorners && m_fancyAvatar )
{
pixmap = *m_fancyAvatar;
}
else if ( m_avatar )
{
pixmap = *m_avatar;
}
if ( !pixmap.isNull() && !size.isEmpty() )
{
if ( m_coverCache[ style ].contains( size.width() ) )
{
return m_coverCache[ style ].value( size.width() );
}
QPixmap scaledCover;
scaledCover = pixmap.scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
QHash< int, QPixmap > innerCache = m_coverCache[ style ];
innerCache.insert( size.width(), scaledCover );
m_coverCache[ style ] = innerCache;
return scaledCover;
}
return pixmap;
}
void
PeerInfo::setVersionString(const QString& versionString)
{
m_versionString = versionString;
}
const QString
PeerInfo::versionString() const
{
return m_versionString;
}
} // ns

View File

@ -0,0 +1,132 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012, Dominik Schmidt <dev@dominik-schmidt.de>
*
* 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 PEERINFO_H
#define PEERINFO_H
#include "DllMacro.h"
#include "SipInfo.h"
#include "accounts/Account.h"
#include "utils/TomahawkUtils.h"
#include <QString>
#include <QPixmap>
#define peerInfoDebug(peerInfo) tDebug() << "PEERINFO:" << ( !peerInfo.isNull() ? peerInfo->debugName() : "Invalid PeerInfo" ).toLatin1().constData()
class SipPlugin;
class ControlConnection;
namespace Tomahawk
{
class DLLEXPORT PeerInfo : public QObject
{
Q_OBJECT
public:
enum Status
{
Online,
Offline
};
enum GetOptions
{
None,
AutoCreate
};
// this is a uberstupid hack, identify characteristics of the type
enum Type
{
External, // this is the default
Local
};
static Tomahawk::peerinfo_ptr get( SipPlugin* parent, const QString& id, GetOptions options = None);
static QList< Tomahawk::peerinfo_ptr > getAll();
virtual ~PeerInfo();
const QString id() const;
SipPlugin* sipPlugin() const;
const QString debugName() const;
void sendLocalSipInfo( const SipInfo& sipInfo );
QWeakPointer< Tomahawk::PeerInfo > weakRef();
void setWeakRef( QWeakPointer< Tomahawk::PeerInfo > weakRef );
void setControlConnection( ControlConnection* controlConnection );
ControlConnection* controlConnection() const;
bool hasControlConnection();
void setType( Tomahawk::PeerInfo::Type type );
PeerInfo::Type type() const;
// actual data
void setStatus( Status status );
Status status() const;
void setSipInfo( const SipInfo& sipInfo );
const SipInfo sipInfo() const;
void setFriendlyName( const QString& friendlyName );
const QString friendlyName() const;
void setAvatar( const QPixmap& avatar );
const QPixmap avatar( TomahawkUtils::ImageMode style = TomahawkUtils::Original, const QSize& size = QSize() ) const;
void setVersionString( const QString& versionString );
const QString versionString() const;
signals:
void sipInfoChanged();
private:
PeerInfo( SipPlugin* parent, const QString& id );
void announce();
static QHash< QString, peerinfo_ptr > s_peersByCacheKey;
QWeakPointer< Tomahawk::PeerInfo > m_ownRef;
QPointer< ControlConnection > m_controlConnection;
PeerInfo::Type m_type;
QString m_id;
Status m_status;
SipInfo m_sipInfo;
QString m_friendlyName;
QString m_versionString;
mutable QPixmap* m_avatar;
mutable QPixmap* m_fancyAvatar;
mutable QByteArray m_avatarHash;
mutable bool m_avatarUpdated;
mutable QHash< TomahawkUtils::ImageMode, QHash< int, QPixmap > > m_coverCache;
};
} // ns
#endif // PEERINFO_H

View File

@ -1,247 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
* Copyright 2010-2011, 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 "SipHandler.h"
#include "sip/SipPlugin.h"
#include <QCoreApplication>
#include <QDir>
#include <QPluginLoader>
#ifndef ENABLE_HEADLESS
#include <QMessageBox>
#endif
#include "database/Database.h"
#include "database/DatabaseImpl.h"
#include "network/ControlConnection.h"
#include "network/Servent.h"
#include "SourceList.h"
#include "TomahawkSettings.h"
#include "utils/Logger.h"
#include "accounts/AccountManager.h"
#include "config.h"
SipHandler* SipHandler::s_instance = 0;
SipHandler*
SipHandler::instance()
{
if ( !s_instance )
new SipHandler( 0 );
return s_instance;
}
SipHandler::SipHandler( QObject* parent )
: QObject( parent )
{
s_instance = this;
}
SipHandler::~SipHandler()
{
qDebug() << Q_FUNC_INFO;
s_instance = 0;
}
#ifndef ENABLE_HEADLESS
const QPixmap
SipHandler::avatar( const QString& name ) const
{
// qDebug() << Q_FUNC_INFO << "Getting avatar" << name; // << m_usernameAvatars.keys();
if( m_usernameAvatars.contains( name ) )
{
// qDebug() << Q_FUNC_INFO << "Getting avatar and avatar != null ";
Q_ASSERT(!m_usernameAvatars.value( name ).isNull());
return m_usernameAvatars.value( name );
}
else
{
// qDebug() << Q_FUNC_INFO << "Getting avatar and avatar == null :-(";
return QPixmap();
}
}
#endif
const SipInfo
SipHandler::sipInfo( const QString& peerId ) const
{
return m_peersSipInfos.value( peerId );
}
const QString
SipHandler::versionString( const QString& peerId ) const
{
return m_peersSoftwareVersions.value( peerId );
}
void
SipHandler::hookUpPlugin( SipPlugin* sip )
{
QObject::connect( sip, SIGNAL( peerOnline( QString ) ), SLOT( onPeerOnline( QString ) ) );
QObject::connect( sip, SIGNAL( peerOffline( QString ) ), SLOT( onPeerOffline( QString ) ) );
QObject::connect( sip, SIGNAL( msgReceived( QString, QString ) ), SLOT( onMessage( QString, QString ) ) );
QObject::connect( sip, SIGNAL( sipInfoReceived( QString, SipInfo ) ), SLOT( onSipInfo( QString, SipInfo ) ) );
QObject::connect( sip, SIGNAL( softwareVersionReceived( QString, QString ) ), SLOT( onSoftwareVersion( QString, QString ) ) );
QObject::connect( sip, SIGNAL( avatarReceived( QString, QPixmap ) ), SLOT( onAvatarReceived( QString, QPixmap ) ) );
QObject::connect( sip, SIGNAL( avatarReceived( QPixmap ) ), SLOT( onAvatarReceived( QPixmap ) ) );
QObject::connect( sip->account(), SIGNAL( configurationChanged() ), sip, SLOT( configurationChanged() ) );
}
void
SipHandler::onPeerOnline( const QString& peerId )
{
// qDebug() << Q_FUNC_INFO;
tDebug() << "SIP online:" << peerId;
SipPlugin* sip = qobject_cast<SipPlugin*>(sender());
SipInfo info;
if( Servent::instance()->visibleExternally() )
{
QString key = uuid();
ControlConnection* conn = new ControlConnection( Servent::instance(), QString() );
const QString& nodeid = Database::instance()->impl()->dbid();
conn->setName( peerId.left( peerId.indexOf( "/" ) ) );
conn->setId( nodeid );
Servent::instance()->registerOffer( key, conn );
info.setVisible( true );
info.setHost( Servent::instance()->externalAddress() );
info.setPort( Servent::instance()->externalPort() );
info.setKey( key );
info.setUniqname( nodeid );
tDebug() << "Asking them to connect to us:" << info;
}
else
{
info.setVisible( false );
tDebug() << "We are not visible externally:" << info;
}
sip->sendMsg( peerId, info );
}
void
SipHandler::onPeerOffline( const QString& peerId )
{
// qDebug() << Q_FUNC_INFO;
tDebug() << "SIP offline:" << peerId;
}
void
SipHandler::onSipInfo( const QString& peerId, const SipInfo& info )
{
tDebug() << Q_FUNC_INFO << "SIP Message:" << peerId << info;
QString barePeerId = peerId.left( peerId.indexOf( "/" ) );
//FIXME: We should probably be using barePeerId in the connectToPeer call below.
//But, verify this doesn't cause any problems (there is still a uniquename after all)
/*
If only one party is externally visible, connection is obvious
If both are, peer with lowest IP address initiates the connection.
This avoids dupe connections.
*/
if ( info.isVisible() )
{
if( !Servent::instance()->visibleExternally() ||
Servent::instance()->externalAddress() < info.host() ||
( Servent::instance()->externalAddress() == info.host() && Servent::instance()->externalPort() < info.port() ) )
{
tDebug() << "Initiate connection to" << peerId << "at" << info.host();
Servent::instance()->connectToPeer( info.host(),
info.port(),
info.key(),
peerId,
info.uniqname() );
}
else
{
tDebug() << Q_FUNC_INFO << "They should be conecting to us...";
}
}
else
{
tDebug() << Q_FUNC_INFO << "They are not visible, doing nothing atm";
}
m_peersSipInfos.insert( peerId, info );
}
void SipHandler::onSoftwareVersion( const QString& peerId, const QString& versionString )
{
m_peersSoftwareVersions.insert( peerId, versionString );
}
void
SipHandler::onMessage( const QString& from, const QString& msg )
{
qDebug() << Q_FUNC_INFO << from << msg;
}
#ifndef ENABLE_HEADLESS
void
SipHandler::onAvatarReceived( const QString& from, const QPixmap& avatar )
{
// qDebug() << Q_FUNC_INFO << "setting avatar on source for" << from;
if ( avatar.isNull() )
{
return;
}
m_usernameAvatars.insert( from, avatar );
ControlConnection *conn = Servent::instance()->lookupControlConnection( from );
if( conn )
{
Tomahawk::source_ptr source = conn->source();
if( source )
{
// qDebug() << Q_FUNC_INFO << from << "got source, setting avatar on source:" << source->friendlyName();
source->setAvatar( avatar );
}
}
}
void
SipHandler::onAvatarReceived( const QPixmap& avatar )
{
// qDebug() << Q_FUNC_INFO << "Set own avatar on MyCollection";
SourceList::instance()->getLocal()->setAvatar( avatar );
}
#endif

View File

@ -1,88 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
* Copyright 2010-2011, 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 SIPHANDLER_H
#define SIPHANDLER_H
#include "sip/SipPlugin.h"
#include "DllMacro.h"
#include <QObject>
#include <QHash>
#include <QString>
#ifndef ENABLE_HEADLESS
#include <QPixmap>
#endif
/**
* Manages SIP plugins for connecting to friends. External interface to SIP plugins is
* through AccountManager, this is an internal class.
*/
class DLLEXPORT SipHandler : public QObject
{
Q_OBJECT
public:
static SipHandler* instance();
SipHandler( QObject* parent );
~SipHandler();
void loadFromAccountManager();
#ifndef ENABLE_HEADLESS
const QPixmap avatar( const QString& name ) const;
#endif
//TODO: implement a proper SipInfo class and maybe attach it to the source
const SipInfo sipInfo( const QString& peerId ) const;
const QString versionString( const QString& peerId ) const;
void hookUpPlugin( SipPlugin* p );
private slots:
void onSipInfo( const QString& peerId, const SipInfo& info );
void onSoftwareVersion( const QString& peerId, const QString& versionString );
void onMessage( const QString&, const QString& );
void onPeerOffline( const QString& );
void onPeerOnline( const QString& );
#ifndef ENABLE_HEADLESS
// set data for local source
void onAvatarReceived( const QPixmap& avatar );
// set data for other sources
void onAvatarReceived( const QString& from, const QPixmap& avatar );
#endif
private:
static SipHandler *s_instance;
//TODO: move this to source
QHash<QString, SipInfo> m_peersSipInfos;
QHash<QString, QString> m_peersSoftwareVersions;
#ifndef ENABLE_HEADLESS
QHash<QString, QPixmap> m_usernameAvatars;
#endif
};
#endif

View File

@ -237,7 +237,8 @@ SipInfo::fromJson( QString json )
}
QDebug operator<< ( QDebug dbg, const SipInfo& info )
QDebug
operator<< ( QDebug dbg, const SipInfo& info )
{
if( !info.isValid() )
dbg.nospace() << "info is invalid";
@ -246,3 +247,31 @@ QDebug operator<< ( QDebug dbg, const SipInfo& info )
return dbg.maybeSpace();
}
bool operator==( const SipInfo& one, const SipInfo& two )
{
// check valid/invalid combinations first, so we don't try to access any invalid sipInfos (->assert)
if( !one.isValid() && !two.isValid() )
{
return true;
}
else if( ( one.isValid() && !two.isValid() ) || ( !one.isValid() && two.isValid() ) )
{
return false;
}
else if( one.isValid() && two.isValid() )
{
if( one.isVisible() == two.isVisible()
&& one.host() == two.host()
&& one.port() == two.port()
&& one.uniqname() == two.uniqname()
&& one.key() == two.key()
)
{
return true;
}
}
return false;
}

View File

@ -64,7 +64,7 @@ private:
};
DLLEXPORT QDebug operator<<( QDebug dbg, const SipInfo &info );
DLLEXPORT bool operator==( const SipInfo& one, const SipInfo& two );
#endif // SIPINFO_H
#endif // SIPINFO_H

View File

@ -23,6 +23,7 @@
#include "utils/Logger.h"
#include "Source.h"
#include "sip/PeerInfo.h"
SipPlugin::SipPlugin() : QObject() {}
@ -32,8 +33,7 @@ SipPlugin::SipPlugin( Tomahawk::Accounts::Account *account, QObject* parent )
: QObject( parent )
, m_account( account )
{
connect( this, SIGNAL( peerOnline( QString ) ), this, SLOT( onPeerOnline( QString ) ) );
connect( this, SIGNAL( peerOffline( QString ) ), this, SLOT( onPeerOffline( QString ) ) );
connect( account, SIGNAL( configurationChanged() ), SLOT( configurationChanged() ) );
}
@ -82,25 +82,16 @@ SipPlugin::account() const
}
const QStringList
const QList< Tomahawk::peerinfo_ptr >
SipPlugin::peersOnline() const
{
return m_peersOnline;
}
void
SipPlugin::onPeerOnline( const QString& peerId )
{
if( !m_peersOnline.contains( peerId ) )
{
m_peersOnline.append( peerId );
}
}
void
SipPlugin::onPeerOffline( const QString& peerId )
{
m_peersOnline.removeAll( peerId );
QList< Tomahawk::peerinfo_ptr > result;
foreach( const Tomahawk::peerinfo_ptr& peerInfo, Tomahawk::PeerInfo::getAll() )
{
if(peerInfo->sipPlugin() == this)
result.append( peerInfo );
}
return result;
}

View File

@ -59,7 +59,7 @@ public:
virtual Tomahawk::Accounts::Account* account() const;
// peer infos
virtual const QStringList peersOnline() const;
virtual const QList< Tomahawk::peerinfo_ptr > peersOnline() const;
public slots:
virtual void connectPlugin() = 0;
@ -67,38 +67,23 @@ public slots:
virtual void checkSettings() = 0;
virtual void configurationChanged() = 0;
virtual void addContact( const QString &jid, const QString& msg = QString() ) = 0;
virtual void sendMsg( const QString& to, const SipInfo& info ) = 0;
virtual void addContact( const QString& peerId, const QString& msg = QString() ) = 0;
virtual void sendSipInfo( const Tomahawk::peerinfo_ptr& receiver, const SipInfo& info ) = 0;
signals:
void peerOnline( const QString& );
void peerOffline( const QString& );
void msgReceived( const QString& from, const QString& msg );
void sipInfoReceived( const QString& peerId, const SipInfo& info );
void softwareVersionReceived( const QString& peerId, const QString& versionString );
void peerOnline( const Tomahawk::peerinfo_ptr& );
void dataError( bool );
#ifndef ENABLE_HEADLESS
// new data for own source
void avatarReceived ( const QPixmap& avatar );
// new data for other sources;
void avatarReceived ( const QString& from, const QPixmap& avatar);
void addMenu( QMenu* menu );
void removeMenu( QMenu* menu );
#endif
void dataError( bool );
private slots:
void onPeerOnline( const QString &peerId );
void onPeerOffline( const QString &peerId );
protected:
Tomahawk::Accounts::Account *m_account;
private:
QStringList m_peersOnline;
};
#endif