1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-01-18 23:17:59 +01:00

* Added TransferView to monitor current streaming activity.

This commit is contained in:
Christian Muehlhaeuser 2010-11-28 12:26:01 +01:00
parent 0718be3848
commit 527f0a43fb
13 changed files with 267 additions and 69 deletions

View File

@ -10,6 +10,7 @@
#include "typedefs.h"
class ControlConnection;
class FileTransferConnection;
namespace Tomahawk
{
@ -71,8 +72,10 @@ private:
QString m_username, m_friendlyname;
unsigned int m_id;
QList< QSharedPointer<Collection> > m_collections;
ControlConnection* m_cc;
QVariantMap m_stats;
ControlConnection* m_cc;
FileTransferConnection* m_ftc;
};
};

View File

@ -140,6 +140,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
infowidgets/sourceinfowidget.cpp
transferview.cpp
tomahawkwindow.cpp
tomahawktrayicon.cpp
audiocontrols.cpp
@ -270,6 +271,7 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
infowidgets/sourceinfowidget.h
transferview.h
tomahawkwindow.h
tomahawktrayicon.h
audiocontrols.h
@ -321,12 +323,6 @@ ENDIF( WIN32 )
IF( UNIX )
INCLUDE( "CMakeLists.unix.txt" )
ENDIF( UNIX )
IF( APPLE )
INCLUDE( "CMakeLists.osx.txt" )
ENDIF( APPLE )
IF( UNIX AND NOT APPLE )
INCLUDE( "CMakeLists.linux.txt" )
ENDIF( UNIX AND NOT APPLE )
kde4_add_app_icon( tomahawkSources "${CMAKE_CURRENT_SOURCE_DIR}/../data/icons/tomahawk-icon-*.png" )
qt4_add_resources( RC_SRCS "../resources.qrc" )

View File

@ -19,3 +19,10 @@ SET( OS_SPECIFIC_LINK_LIBRARIES
ogg
FLAC++
)
IF( APPLE )
INCLUDE( "CMakeLists.osx.txt" )
ENDIF( APPLE )
IF( UNIX AND NOT APPLE )
INCLUDE( "CMakeLists.linux.txt" )
ENDIF( UNIX AND NOT APPLE )

View File

@ -90,7 +90,7 @@ void
ControlConnection::registerSource()
{
qDebug() << Q_FUNC_INFO;
Source * source = (Source*) sender();
Source* source = (Source*) sender();
Q_ASSERT( source == m_source.data() );
// .. but we'll use the shared pointer we've already made:
@ -100,7 +100,7 @@ ControlConnection::registerSource()
m_registered = true;
setupDbSyncConnection();
m_servent->registerControlConnection(this);
m_servent->registerControlConnection( this );
}
@ -176,7 +176,7 @@ ControlConnection::handleMsg( msg_ptr msg )
{
if ( msg->is( Msg::PING ) )
{
qDebug() << "Received Connection PING, nice." << m_pingtimer_mark.elapsed();
// qDebug() << "Received Connection PING, nice." << m_pingtimer_mark.elapsed();
m_pingtimer_mark.restart();
return;
}

View File

@ -46,8 +46,9 @@ FileTransferConnection::FileTransferConnection( Servent* s, ControlConnection* c
}
FileTransferConnection::FileTransferConnection( Servent* s, QString fid )
FileTransferConnection::FileTransferConnection( Servent* s, ControlConnection* cc, QString fid )
: Connection( s )
, m_cc( cc )
, m_fid( fid )
, m_type( SENDING )
, m_badded( 0 )
@ -74,7 +75,7 @@ FileTransferConnection::~FileTransferConnection()
((BufferIODevice*)m_iodev.data())->inputComplete();
}
APP->servent().fileTransferFinished( this );
APP->servent().onFileTransferFinished( this );
}
@ -96,12 +97,29 @@ FileTransferConnection::showStats( qint64 tx, qint64 rx )
<< QString( "Down: %L1 bytes/sec," ).arg( rx )
<< QString( "Up: %L1 bytes/sec" ).arg( tx );
}
m_transferRate = tx + rx;
emit updated();
}
void
FileTransferConnection::setup()
{
QList<source_ptr> sources = APP->sourcelist().sources();
foreach( const source_ptr& src, sources )
{
// local src doesnt have a control connection, skip it:
if( src.isNull() || src->isLocal() )
continue;
if ( src->controlConnection() == m_cc )
{
m_source = src;
break;
}
}
connect( this, SIGNAL( statsTick( qint64, qint64 ) ), SLOT( showStats( qint64, qint64 ) ) );
if( m_type == RECEIVING )
{
@ -118,17 +136,19 @@ FileTransferConnection::setup()
void
FileTransferConnection::startSending( QVariantMap f )
FileTransferConnection::startSending( const QVariantMap& f )
{
Tomahawk::result_ptr result( new Tomahawk::Result( f, collection_ptr() ) );
qDebug() << "Starting to transmit" << result->url();
QSharedPointer<QIODevice> io = TomahawkApp::instance()->getIODeviceForUrl( result );
m_result = Tomahawk::result_ptr( new Tomahawk::Result( f, collection_ptr() ) );
qDebug() << "Starting to transmit" << m_result->url();
QSharedPointer<QIODevice> io = TomahawkApp::instance()->getIODeviceForUrl( m_result );
if( !io )
{
qDebug() << "Couldn't read from source:" << result->url();
qDebug() << "Couldn't read from source:" << m_result->url();
shutdown();
return;
}
m_readdev = QSharedPointer<QIODevice>( io );
sendSome();
}

View File

@ -6,6 +6,7 @@
#include <QIODevice>
#include "connection.h"
#include "tomahawk/result.h"
class ControlConnection;
class BufferIODevice;
@ -22,9 +23,9 @@ public:
};
// RX:
explicit FileTransferConnection( Servent* s, ControlConnection* parent, QString fid, unsigned int size );
explicit FileTransferConnection( Servent* s, ControlConnection* cc, QString fid, unsigned int size );
// TX:
explicit FileTransferConnection( Servent* s, QString fid );
explicit FileTransferConnection( Servent* s, ControlConnection* cc, QString fid );
virtual ~FileTransferConnection();
@ -33,15 +34,23 @@ public:
Connection* clone();
const QSharedPointer<QIODevice>& iodevice() { return m_iodev; }
ControlConnection* controlConnection() const { return m_cc; }
Tomahawk::source_ptr source() const { return m_source; }
Tomahawk::result_ptr track() const { return m_result; }
qint64 transferRate() const { return m_transferRate; }
Type type() const { return m_type; }
QString fid() const { return m_fid; }
signals:
void updated();
protected slots:
virtual void handleMsg( msg_ptr msg );
private slots:
void startSending( QVariantMap );
void startSending( const QVariantMap& );
void sendSome();
void showStats(qint64 tx, qint64 rx);
@ -54,6 +63,10 @@ private:
int m_badded, m_bsent;
bool m_allok; // got last msg ok, transfer complete?
Tomahawk::source_ptr m_source;
Tomahawk::result_ptr m_result;
qint64 m_transferRate;
};
#endif // FILETRANSFERCONNECTION_H

View File

@ -121,9 +121,10 @@ QString
Servent::createConnectionKey( const QString& name )
{
Q_ASSERT( this->thread() == QThread::currentThread() );
QString key = uuid();
ControlConnection * cc = new ControlConnection( this );
cc->setName( name=="" ? QString( "KEY(%1)" ).arg(key) : name );
cc->setName( name.isEmpty() ? QString( "KEY(%1)" ).arg( key ) : name );
registerOffer( key, cc );
return key;
}
@ -227,37 +228,51 @@ Servent::readyRead()
sock->_msg->fill( ba );
Q_ASSERT( sock->_msg->is( Msg::JSON ) );
ControlConnection* cc = 0;
bool ok;
int pport = 0;
QString key, conntype, nodeid;
QString key, conntype, nodeid, controlid;
QVariantMap m = parser.parse( sock->_msg->payload(), &ok ).toMap();
if( !ok )
{
qDebug() << "Invalid JSON on new conection, aborting";
goto closeconnection;
}
conntype = m.value( "conntype" ).toString();
key = m.value( "key" ).toString();
pport = m.value( "port" ).toInt();
nodeid = m.value( "nodeid" ).toString();
conntype = m.value( "conntype" ).toString();
key = m.value( "key" ).toString();
pport = m.value( "port" ).toInt();
nodeid = m.value( "nodeid" ).toString();
controlid = m.value( "controlid" ).toString();
qDebug() << m;
if( !nodeid.isEmpty() ) // only control connections send nodeid
foreach( ControlConnection* cc, m_controlconnections )
if( !nodeid.isEmpty() && cc != 0 ) // only control connections send nodeid
{
if( cc->id() == nodeid )
foreach( ControlConnection* con, m_controlconnections )
{
qDebug() << "Duplicate control connection detected, dropping:" << nodeid << conntype;
goto closeconnection;
qDebug() << con->socket() << sock;
if( con->id() == nodeid )
{
qDebug() << "Duplicate control connection detected, dropping:" << nodeid << conntype;
goto closeconnection;
}
}
}
foreach( ControlConnection* con, m_controlconnections )
{
qDebug() << "cons:" << con;
qDebug() << "conid:" << con->id();
if ( con->id() == controlid )
cc = con;
}
// they connected to us and want something we are offering
if( conntype == "accept-offer" || "push-offer" )
{
sock->_msg.clear();
Connection * conn = claimOffer( key, sock->peerAddress() );
Connection* conn = claimOffer( cc, key, sock->peerAddress() );
if( !conn )
{
qDebug() << "claimOffer FAILED, key:" << key;
@ -265,10 +280,10 @@ Servent::readyRead()
}
qDebug() << "claimOffer OK:" << key;
if( !nodeid.isEmpty() ) conn->setId( nodeid );
if( !nodeid.isEmpty() )
conn->setId( nodeid );
handoverSocket( conn, sock );
return;
}
else
@ -310,6 +325,7 @@ Servent::createParallelConnection( Connection* orig_conn, Connection* new_conn,
m.insert( "key", tmpkey );
m.insert( "offer", key );
m.insert( "port", externalPort() );
m.insert( "controlid", orig_conn->id() );
QJson::Serializer ser;
orig_conn->sendMsg( Msg::factory( ser.serialize(m), Msg::JSON ) );
@ -383,10 +399,10 @@ Servent::connectToPeer( const QString& ha, int port, const QString &key, const Q
ControlConnection* conn = new ControlConnection( this );
QVariantMap m;
m["conntype"] = "accept-offer";
m["key"] = key;
m["port"] = externalPort();
m["nodeid"] = APP->nodeID();
m["conntype"] = "accept-offer";
m["key"] = key;
m["port"] = externalPort();
m["nodeid"] = APP->nodeID();
conn->setFirstMessage( m );
if( name.length() )
@ -411,9 +427,10 @@ Servent::connectToPeer( const QString& ha, int port, const QString &key, Connect
if( key.length() && conn->firstMessage().isNull() )
{
QVariantMap m;
m["conntype"] = "accept-offer";
m["key"] = key;
m["port"] = externalPort();
m["conntype"] = "accept-offer";
m["key"] = key;
m["port"] = externalPort();
m["controlid"] = APP->nodeID();
conn->setFirstMessage( m );
}
@ -435,13 +452,13 @@ Servent::connectToPeer( const QString& ha, int port, const QString &key, Connect
void
Servent::reverseOfferRequest( Connection* orig_conn, const QString& key, const QString& theirkey )
Servent::reverseOfferRequest( ControlConnection* orig_conn, const QString& key, const QString& theirkey )
{
Q_ASSERT( this->thread() == QThread::currentThread() );
qDebug() << "Servent::reverseOfferRequest received for" << key;
Connection * new_conn = claimOffer( key );
if( !new_conn )
Connection* new_conn = claimOffer( orig_conn, key );
if ( !new_conn )
{
qDebug() << "claimOffer failed, killing requesting connection out of spite";
orig_conn->shutdown();
@ -449,9 +466,10 @@ Servent::reverseOfferRequest( Connection* orig_conn, const QString& key, const Q
}
QVariantMap m;
m["conntype"] = "push-offer";
m["key"] = theirkey;
m["port"] = externalPort();
m["conntype"] = "push-offer";
m["key"] = theirkey;
m["port"] = externalPort();
m["controlid"] = orig_conn->id();
new_conn->setFirstMessage( m );
createParallelConnection( orig_conn, new_conn, QString() );
}
@ -459,12 +477,12 @@ Servent::reverseOfferRequest( Connection* orig_conn, const QString& key, const Q
// return the appropriate connection for a given offer key, or NULL if invalid
Connection*
Servent::claimOffer( const QString &key, const QHostAddress peer )
Servent::claimOffer( ControlConnection* cc, const QString &key, const QHostAddress peer )
{
bool noauth = qApp->arguments().contains( "--noauth" );
// magic key for file transfers:
if( key.startsWith("FILE_REQUEST_KEY:") )
if( key.startsWith( "FILE_REQUEST_KEY:" ) )
{
// check if the source IP matches an existing, authenticated connection
if ( !noauth && peer != QHostAddress::Any && !isIPWhitelisted( peer ) )
@ -486,13 +504,13 @@ Servent::claimOffer( const QString &key, const QHostAddress peer )
}
QString fid = key.right( key.length() - 17 );
FileTransferConnection* ftc = new FileTransferConnection( this, fid );
FileTransferConnection* ftc = new FileTransferConnection( this, cc, fid );
return ftc;
}
if( key == "whitelist" ) // LAN IP address, check source IP
{
if( isIPWhitelisted(peer) )
if( isIPWhitelisted( peer ) )
{
qDebug() << "Connection is from whitelisted IP range (LAN)";
Connection* conn = new ControlConnection( this );
@ -567,23 +585,28 @@ void
Servent::registerFileTransferConnection( FileTransferConnection* ftc )
{
Q_ASSERT( !m_ftsessions.contains( ftc ) );
QMutexLocker lock( &m_ftsession_mut );
qDebug() << "Registering FileTransfer" << m_ftsessions.length() + 1;
QMutexLocker lock( &m_ftsession_mut );
m_ftsessions.append( ftc );
printCurrentTransfers();
emit fileTransferStarted( ftc );
}
void
Servent::fileTransferFinished( FileTransferConnection* ftc )
Servent::onFileTransferFinished( FileTransferConnection* ftc )
{
Q_ASSERT( ftc );
qDebug() << "FileTransfer Finished, unregistering" << ftc->id();
QMutexLocker lock( &m_ftsession_mut );
int rem = m_ftsessions.removeAll( ftc );
Q_ASSERT( rem == 1 );
printCurrentTransfers();
emit fileTransferFinished( ftc );
}
@ -608,11 +631,11 @@ Servent::isIPWhitelisted( QHostAddress ip )
static QList<range> whitelist;
if( whitelist.isEmpty() )
{
whitelist << range( QHostAddress("10.0.0.0"), 8 )
<< range( QHostAddress("172.16.0.0"), 12 )
<< range( QHostAddress("192.168.0.0"), 16 )
<< range( QHostAddress("169.254.0.0"), 16 )
<< range( QHostAddress("127.0.0.0"), 24 );
whitelist << range( QHostAddress( "10.0.0.0" ), 8 )
<< range( QHostAddress( "172.16.0.0" ), 12 )
<< range( QHostAddress( "192.168.0.0" ), 16 )
<< range( QHostAddress( "169.254.0.0" ), 16 )
<< range( QHostAddress( "127.0.0.0" ), 24 );
// qDebug() << "Loaded whitelist IP range:" << whitelist;
}

View File

@ -82,7 +82,7 @@ public:
void connectToPeer( const QString& ha, int port, const QString &key, const QString& name = "", const QString& id = "" );
void connectToPeer( const QString& ha, int port, const QString &key, Connection* conn );
void reverseOfferRequest( Connection* orig_conn, const QString& key, const QString& theirkey );
void reverseOfferRequest( ControlConnection* orig_conn, const QString& key, const QString& theirkey );
void setExternalAddress( QHostAddress ha, int port );
bool visibleExternally() const { return m_externalPort > 0; }
@ -93,9 +93,14 @@ public:
static bool isIPWhitelisted( QHostAddress ip );
bool connectedToSession( const QString& session );
unsigned int numConnectedPeers() const { return m_controlconnections.length(); }
QList< FileTransferConnection* > fileTransfers() const { return m_ftsessions; }
signals:
void fileTransferStarted( FileTransferConnection* );
void fileTransferFinished( FileTransferConnection* );
protected:
void incomingConnection( int sd );
@ -104,7 +109,7 @@ public slots:
void createParallelConnection( Connection* orig_conn, Connection* new_conn, const QString& key );
void registerFileTransferConnection( FileTransferConnection* );
void fileTransferFinished( FileTransferConnection* ftc );
void onFileTransferFinished( FileTransferConnection* ftc );
void socketConnected();
void triggerDBSync();
@ -112,7 +117,7 @@ public slots:
private slots:
void readyRead();
Connection* claimOffer( const QString &key, const QHostAddress peer = QHostAddress::Any );
Connection* claimOffer( ControlConnection* cc, const QString &key, const QHostAddress peer = QHostAddress::Any );
private:
void handoverSocket( Connection* conn, QTcpSocketExtra* sock );

View File

@ -18,6 +18,7 @@ Source::Source( const QString &username, ControlConnection* cc )
, m_username( username )
, m_id( 0 )
, m_cc( cc )
, m_ftc( 0 )
{
// source for local machine doesn't have a controlconnection. this is normal.
if ( cc )

View File

@ -65,6 +65,9 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
ui->splitter->setStretchFactor( 0, 1 );
ui->splitter->setStretchFactor( 1, 3 );
ui->splitter_2->setStretchFactor( 0, 3 );
ui->splitter_2->setStretchFactor( 1, 1 );
QToolBar* toolbar = addToolBar( "TomahawkToolbar" );
toolbar->setObjectName( "TomahawkToolbar" );
toolbar->addWidget( m_topbar );

View File

@ -20,13 +20,19 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="SourceTreeView" name="sourceTreeView">
<property name="minimumSize">
<size>
<width>250</width>
<height>0</height>
</size>
<widget class="AnimatedSplitter" name="splitter_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="SourceTreeView" name="sourceTreeView">
<property name="minimumSize">
<size>
<width>250</width>
<height>0</height>
</size>
</property>
</widget>
<widget class="TransferView" name="treeWidget"/>
</widget>
<widget class="QWidget" name="playlistWidget" native="true"/>
</widget>
@ -144,6 +150,17 @@
<extends>QTreeView</extends>
<header>sourcetreeview.h</header>
</customwidget>
<customwidget>
<class>AnimatedSplitter</class>
<extends>QSplitter</extends>
<header location="global">animatedsplitter.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>TransferView</class>
<extends>QTreeWidget</extends>
<header>transferview.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>

74
src/transferview.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "transferview.h"
#include <QHeaderView>
#include "tomahawk/tomahawkapp.h"
#include "network/filetransferconnection.h"
#include "network/servent.h"
TransferView::TransferView( QWidget* parent )
: QTreeWidget( parent )
{
connect( &APP->servent(), SIGNAL( fileTransferStarted( FileTransferConnection* ) ), SLOT( fileTransferRegistered( FileTransferConnection* ) ) );
connect( &APP->servent(), SIGNAL( fileTransferFinished( FileTransferConnection* ) ), SLOT( fileTransferFinished( FileTransferConnection* ) ) );
QStringList headers;
headers << tr( "Peer" ) << tr( "Rate" ) << tr( "Track" );
setHeaderLabels( headers );
setColumnCount( 3 );
setColumnWidth( 0, 80 );
setColumnWidth( 1, 65 );
setColumnWidth( 2, 10 );
header()->setStretchLastSection( true );
setRootIsDecorated( false );
}
void
TransferView::fileTransferRegistered( FileTransferConnection* ftc )
{
connect( ftc, SIGNAL( updated() ), SLOT( onTransferUpdate() ) );
}
void
TransferView::fileTransferFinished( FileTransferConnection* ftc )
{
if ( !m_index.contains( ftc ) )
return;
/* int i = m_index.take( ftc );
delete invisibleRootItem()->takeChild( i ); */
if ( m_index.contains( ftc ) )
{
int i = m_index.value( ftc );
invisibleRootItem()->child( i )->setText( 1, tr( "Finished" ) );
}
}
void
TransferView::onTransferUpdate()
{
FileTransferConnection* ftc = (FileTransferConnection*)sender();
QTreeWidgetItem* ti = 0;
if ( m_index.contains( ftc ) )
{
int i = m_index.value( ftc );
ti = invisibleRootItem()->child( i );
}
else
{
ti = new QTreeWidgetItem( this );
m_index.insert( ftc, invisibleRootItem()->childCount() - 1 );
}
ti->setText( 0, ftc->source()->friendlyName() );
ti->setText( 1, QString( "%1 kb/s" ).arg( ftc->transferRate() / 1024 ) );
ti->setText( 2, QString( "%1 - %2" ).arg( ftc->track()->artist()->name() ).arg( ftc->track()->track() ) );
}

36
src/transferview.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef TRANSFERVIEW_H
#define TRANSFERVIEW_H
#include <QDebug>
#include <QTreeWidget>
#include "tomahawk/typedefs.h"
class FileTransferConnection;
class TransferView : public QTreeWidget
{
Q_OBJECT
public:
explicit TransferView( QWidget* parent = 0 );
virtual ~TransferView()
{
qDebug() << Q_FUNC_INFO;
}
signals:
public slots:
private slots:
void fileTransferRegistered( FileTransferConnection* ftc );
void fileTransferFinished( FileTransferConnection* ftc );
void onTransferUpdate();
private:
QHash< FileTransferConnection*, int > m_index;
};
#endif // TRANSFERVIEW_H