~ubuntu-branches/ubuntu/trusty/tomahawk/trusty-proposed

« back to all changes in this revision

Viewing changes to src/libtomahawk/infosystem/InfoSystemWorker.cpp

  • Committer: Package Import Robot
  • Author(s): Harald Sitter
  • Date: 2013-03-07 21:50:13 UTC
  • Revision ID: package-import@ubuntu.com-20130307215013-6gdjkdds7i9uenvs
Tags: upstream-0.6.0+dfsg
ImportĀ upstreamĀ versionĀ 0.6.0+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
 
2
 *
 
3
 *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
 
4
 *   Copyright 2012       Leo Franchi <lfranchi@kde.org>
 
5
 *   Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
 
6
 *
 
7
 *   Tomahawk is free software: you can redistribute it and/or modify
 
8
 *   it under the terms of the GNU General Public License as published by
 
9
 *   the Free Software Foundation, either version 3 of the License, or
 
10
 *   (at your option) any later version.
 
11
 *
 
12
 *   Tomahawk is distributed in the hope that it will be useful,
 
13
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
15
 *   GNU General Public License for more details.
 
16
 *
 
17
 *   You should have received a copy of the GNU General Public License
 
18
 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 
19
 */
 
20
 
 
21
#include "InfoSystemWorker.h"
 
22
 
 
23
#include "config.h"
 
24
#include "InfoSystemCache.h"
 
25
#include "GlobalActionManager.h"
 
26
#include "utils/TomahawkUtils.h"
 
27
#include "utils/Logger.h"
 
28
#include "Source.h"
 
29
 
 
30
 
 
31
#include <QCoreApplication>
 
32
#include <QDir>
 
33
#include <QLibrary>
 
34
#include <QNetworkConfiguration>
 
35
#include <QNetworkProxy>
 
36
#include <QPluginLoader>
 
37
 
 
38
namespace Tomahawk
 
39
{
 
40
 
 
41
namespace InfoSystem
 
42
{
 
43
 
 
44
InfoSystemWorker::InfoSystemWorker()
 
45
    : QObject()
 
46
{
 
47
    tDebug() << Q_FUNC_INFO;
 
48
 
 
49
    m_checkTimeoutsTimer.setInterval( 1000 );
 
50
    m_checkTimeoutsTimer.setSingleShot( false );
 
51
    connect( &m_checkTimeoutsTimer, SIGNAL( timeout() ), SLOT( checkTimeoutsTimerFired() ) );
 
52
    m_checkTimeoutsTimer.start();
 
53
}
 
54
 
 
55
 
 
56
InfoSystemWorker::~InfoSystemWorker()
 
57
{
 
58
    tDebug() << Q_FUNC_INFO << " beginning";
 
59
    Q_FOREACH( InfoPluginPtr plugin, m_plugins )
 
60
    {
 
61
        if( plugin )
 
62
            delete plugin.data();
 
63
    }
 
64
    tDebug() << Q_FUNC_INFO << " finished";
 
65
}
 
66
 
 
67
 
 
68
void
 
69
InfoSystemWorker::init( Tomahawk::InfoSystem::InfoSystemCache* cache )
 
70
{
 
71
    tDebug() << Q_FUNC_INFO;
 
72
    m_shortLinksWaiting = 0;
 
73
    m_cache = cache;
 
74
 
 
75
    loadInfoPlugins( findInfoPlugins() );
 
76
}
 
77
 
 
78
 
 
79
void
 
80
InfoSystemWorker::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin )
 
81
{
 
82
    tDebug() << Q_FUNC_INFO << plugin;
 
83
    foreach ( InfoPluginPtr ptr, m_plugins )
 
84
    {
 
85
        if ( ptr == plugin )
 
86
        {
 
87
            tDebug() << Q_FUNC_INFO << "This plugin is already added to the infosystem.";
 
88
            return;
 
89
        }
 
90
    }
 
91
 
 
92
    if ( plugin.isNull() )
 
93
    {
 
94
        tDebug() << Q_FUNC_INFO << "passed-in plugin is null";
 
95
        return;
 
96
    }
 
97
 
 
98
    plugin.data()->moveToThread( this->thread() );
 
99
    m_plugins.append( plugin );
 
100
    registerInfoTypes( plugin, plugin.data()->supportedGetTypes(), plugin.data()->supportedPushTypes() );
 
101
 
 
102
    connect(
 
103
        plugin.data(),
 
104
            SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
 
105
            this,
 
106
            SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
 
107
            Qt::QueuedConnection
 
108
    );
 
109
 
 
110
    connect(
 
111
        plugin.data(),
 
112
            SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) ),
 
113
            m_cache,
 
114
            SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) ),
 
115
            Qt::QueuedConnection
 
116
    );
 
117
    connect(
 
118
        plugin.data(),
 
119
            SIGNAL( updateCache( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
 
120
            m_cache,
 
121
            SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
 
122
            Qt::QueuedConnection
 
123
    );
 
124
    
 
125
    QMetaObject::invokeMethod( plugin.data(), "init", Qt::QueuedConnection );
 
126
 
 
127
    emit updatedSupportedGetTypes( QSet< InfoType >::fromList( m_infoGetMap.keys() ) );
 
128
    emit updatedSupportedPushTypes( QSet< InfoType >::fromList( m_infoPushMap.keys() ) );
 
129
}
 
130
 
 
131
 
 
132
void
 
133
InfoSystemWorker::removeInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin )
 
134
{
 
135
    tDebug() << Q_FUNC_INFO << plugin;
 
136
 
 
137
    if ( plugin.isNull() )
 
138
    {
 
139
        tDebug() << Q_FUNC_INFO << "passed-in plugin is null";
 
140
        return;
 
141
    }
 
142
 
 
143
    foreach ( InfoPluginPtr ptr, m_plugins )
 
144
    {
 
145
        if ( ptr == plugin )
 
146
            break;
 
147
 
 
148
        tDebug() << Q_FUNC_INFO << "This plugin does not exist in the infosystem.";
 
149
        return;
 
150
    }
 
151
 
 
152
    m_plugins.removeOne( plugin );
 
153
    deregisterInfoTypes( plugin, plugin.data()->supportedGetTypes(), plugin.data()->supportedPushTypes() );
 
154
    delete plugin.data();
 
155
}
 
156
 
 
157
 
 
158
QStringList
 
159
InfoSystemWorker::findInfoPlugins()
 
160
{
 
161
    QStringList paths;
 
162
    QList< QDir > pluginDirs;
 
163
 
 
164
    QDir appDir( qApp->applicationDirPath() );
 
165
#ifdef Q_WS_MAC
 
166
    if ( appDir.dirName() == "MacOS" )
 
167
    {
 
168
        // Development convenience-hack
 
169
        appDir.cdUp();
 
170
        appDir.cdUp();
 
171
        appDir.cdUp();
 
172
    }
 
173
#endif
 
174
 
 
175
    QDir libDir( CMAKE_INSTALL_PREFIX "/lib" );
 
176
 
 
177
    QDir lib64Dir( appDir );
 
178
    lib64Dir.cdUp();
 
179
    lib64Dir.cd( "lib64" );
 
180
 
 
181
    pluginDirs << appDir << libDir << lib64Dir << QDir( qApp->applicationDirPath() );
 
182
    foreach ( const QDir& pluginDir, pluginDirs )
 
183
    {
 
184
        tDebug() << Q_FUNC_INFO << "Checking directory for plugins:" << pluginDir;
 
185
        foreach ( QString fileName, pluginDir.entryList( QStringList() << "*tomahawk_infoplugin_*.so" << "*tomahawk_infoplugin_*.dylib" << "*tomahawk_infoplugin_*.dll", QDir::Files ) )
 
186
        {
 
187
            if ( fileName.startsWith( "libtomahawk_infoplugin" ) )
 
188
            {
 
189
                const QString path = pluginDir.absoluteFilePath( fileName );
 
190
                if ( !paths.contains( path ) )
 
191
                    paths << path;
 
192
            }
 
193
        }
 
194
    }
 
195
 
 
196
    return paths;
 
197
}
 
198
 
 
199
 
 
200
void
 
201
InfoSystemWorker::loadInfoPlugins( const QStringList& pluginPaths )
 
202
{
 
203
    tDebug() << Q_FUNC_INFO << "Attempting to load the following plugin paths:" << pluginPaths;
 
204
 
 
205
    if ( pluginPaths.isEmpty() )
 
206
        return;
 
207
 
 
208
    foreach ( const QString fileName, pluginPaths )
 
209
    {
 
210
        if ( !QLibrary::isLibrary( fileName ) )
 
211
            continue;
 
212
 
 
213
        tDebug() << Q_FUNC_INFO << "Trying to load plugin:" << fileName;
 
214
 
 
215
        QPluginLoader loader( fileName );
 
216
        QObject* plugin = loader.instance();
 
217
        if ( !plugin )
 
218
        {
 
219
            tDebug() << Q_FUNC_INFO << "Error loading plugin:" << loader.errorString();
 
220
            continue;
 
221
        }
 
222
 
 
223
        InfoPlugin* infoPlugin = qobject_cast< InfoPlugin* >( plugin );
 
224
        if ( infoPlugin )
 
225
        {
 
226
            tDebug() << Q_FUNC_INFO << "Loaded info plugin:" << loader.fileName();
 
227
            addInfoPlugin( InfoPluginPtr( infoPlugin ) );
 
228
        }
 
229
        else
 
230
            tDebug() << Q_FUNC_INFO << "Loaded invalid plugin:" << loader.fileName();
 
231
    }
 
232
}
 
233
 
 
234
 
 
235
void
 
236
InfoSystemWorker::registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType >& getTypes, const QSet< InfoType >& pushTypes )
 
237
{
 
238
    Q_FOREACH( InfoType type, getTypes )
 
239
        m_infoGetMap[type].append( plugin );
 
240
    Q_FOREACH( InfoType type, pushTypes )
 
241
        m_infoPushMap[type].append( plugin );
 
242
}
 
243
 
 
244
 
 
245
void
 
246
InfoSystemWorker::deregisterInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType >& getTypes, const QSet< InfoType >& pushTypes )
 
247
{
 
248
    Q_FOREACH( InfoType type, getTypes )
 
249
        m_infoGetMap[type].removeOne( plugin );
 
250
    Q_FOREACH( InfoType type, pushTypes )
 
251
        m_infoPushMap[type].removeOne( plugin );
 
252
}
 
253
 
 
254
 
 
255
QList< InfoPluginPtr >
 
256
InfoSystemWorker::determineOrderedMatches( const InfoType type ) const
 
257
{
 
258
    //Dummy function for now that returns the various items in the QSet; at some point this will
 
259
    //probably need to support ordering based on the data source
 
260
    QList< InfoPluginPtr > providers;
 
261
    Q_FOREACH( InfoPluginPtr ptr, m_infoGetMap[type] )
 
262
        providers << ptr;
 
263
    return providers;
 
264
}
 
265
 
 
266
 
 
267
void
 
268
InfoSystemWorker::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
 
269
{
 
270
    //qDebug() << Q_FUNC_INFO << "type is " << requestData.type << " and allSources = " << (allSources ? "true" : "false" );
 
271
 
 
272
    QList< InfoPluginPtr > providers = determineOrderedMatches( requestData.type );
 
273
    if ( providers.isEmpty() )
 
274
    {
 
275
        emit info( requestData, QVariant() );
 
276
        checkFinished( requestData );
 
277
        return;
 
278
    }
 
279
 
 
280
    if ( !requestData.allSources )
 
281
        providers = QList< InfoPluginPtr >( providers.mid( 0, 1 ) );
 
282
 
 
283
    bool foundOne = false;
 
284
    foreach ( InfoPluginPtr ptr, providers )
 
285
    {
 
286
        if ( !ptr )
 
287
            continue;
 
288
 
 
289
        foundOne = true;
 
290
 
 
291
        if ( requestData.allSources || m_savedRequestMap.contains( requestData.requestId ) )
 
292
        {
 
293
            if ( m_savedRequestMap.contains( requestData.requestId ) )
 
294
                tDebug() << Q_FUNC_INFO << "Warning: reassigning requestId because it already exists";
 
295
            requestData.internalId = TomahawkUtils::infosystemRequestId();
 
296
        }
 
297
        else
 
298
            requestData.internalId = requestData.requestId;
 
299
 
 
300
        quint64 requestId = requestData.internalId;
 
301
        m_requestSatisfiedMap[ requestId ] = false;
 
302
        if ( requestData.timeoutMillis != 0 )
 
303
        {
 
304
            qint64 currMs = QDateTime::currentMSecsSinceEpoch();
 
305
            m_timeRequestMapper.insert( currMs + requestData.timeoutMillis, requestId );
 
306
        }
 
307
    //    qDebug() << "Assigning request with requestId" << requestId << "and type" << requestData.type;
 
308
        m_dataTracker[ requestData.caller ][ requestData.type ] = m_dataTracker[ requestData.caller ][ requestData.type ] + 1;
 
309
    //    qDebug() << "Current count in dataTracker for target" << requestData.caller << "and type" << requestData.type << "is" << m_dataTracker[ requestData.caller ][ requestData.type ];
 
310
 
 
311
        InfoRequestData* data = new InfoRequestData;
 
312
        data->caller = requestData.caller;
 
313
        data->type = requestData.type;
 
314
        data->input = requestData.input;
 
315
        data->customData = requestData.customData;
 
316
        m_savedRequestMap[ requestId ] = data;
 
317
 
 
318
        QMetaObject::invokeMethod( ptr.data(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
 
319
    }
 
320
 
 
321
    if ( !foundOne )
 
322
    {
 
323
        emit info( requestData, QVariant() );
 
324
        checkFinished( requestData );
 
325
    }
 
326
}
 
327
 
 
328
 
 
329
void
 
330
InfoSystemWorker::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData )
 
331
{
 
332
    tDebug() << Q_FUNC_INFO << "type is " << pushData.type;
 
333
 
 
334
    if ( pushData.pushFlags != PushNoFlag )
 
335
    {
 
336
        if ( pushData.pushFlags & PushShortUrlFlag )
 
337
        {
 
338
            pushData.pushFlags = Tomahawk::InfoSystem::PushInfoFlags( pushData.pushFlags & ~PushShortUrlFlag );
 
339
            QMetaObject::invokeMethod( this, "getShortUrl", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPushData, pushData ) );
 
340
            return;
 
341
        }
 
342
    }
 
343
 
 
344
    tDebug() << Q_FUNC_INFO << "number of matching plugins: " << m_infoPushMap[ pushData.type ].size();
 
345
 
 
346
    Q_FOREACH( InfoPluginPtr ptr, m_infoPushMap[ pushData.type ] )
 
347
    {
 
348
        if( ptr )
 
349
            QMetaObject::invokeMethod( ptr.data(), "pushInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPushData, pushData ) );
 
350
    }
 
351
}
 
352
 
 
353
 
 
354
void
 
355
InfoSystemWorker::getShortUrl( Tomahawk::InfoSystem::InfoPushData pushData )
 
356
{
 
357
    tDebug() << Q_FUNC_INFO << "type is " << pushData.type;
 
358
    if ( !pushData.infoPair.second.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
 
359
    {
 
360
        QMetaObject::invokeMethod( this, "pushInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPushData, pushData ) );
 
361
        return;
 
362
    }
 
363
 
 
364
    Tomahawk::InfoSystem::InfoStringHash hash = pushData.infoPair.second.value< Tomahawk::InfoSystem::InfoStringHash >();
 
365
 
 
366
    if ( hash.isEmpty() || !hash.contains( "title" ) || !hash.contains( "artist" ) )
 
367
    {
 
368
        QMetaObject::invokeMethod( this, "pushInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPushData, pushData ) );
 
369
        return;
 
370
    }
 
371
 
 
372
    QString title, artist, album;
 
373
    title = hash[ "title" ];
 
374
    artist = hash[ "artist" ];
 
375
    if( hash.contains( "album" ) )
 
376
        album = hash[ "album" ];
 
377
 
 
378
    QUrl longUrl = GlobalActionManager::instance()->openLink( title, artist, album );
 
379
 
 
380
    GlobalActionManager::instance()->shortenLink( longUrl, QVariant::fromValue< Tomahawk::InfoSystem::InfoPushData >( pushData ) );
 
381
    connect( GlobalActionManager::instance(), SIGNAL( shortLinkReady( QUrl, QUrl, QVariant ) ), this, SLOT( shortLinkReady( QUrl, QUrl, QVariant ) ), Qt::UniqueConnection );
 
382
    m_shortLinksWaiting++;
 
383
}
 
384
 
 
385
 
 
386
void
 
387
InfoSystemWorker::shortLinkReady( QUrl longUrl, QUrl shortUrl, QVariant callbackObj )
 
388
{
 
389
    tDebug() << Q_FUNC_INFO << "long url = " << longUrl << ", shortUrl = " << shortUrl;
 
390
    m_shortLinksWaiting--;
 
391
    if ( !m_shortLinksWaiting )
 
392
        disconnect( GlobalActionManager::instance(), SIGNAL( shortLinkReady( QUrl, QUrl, QVariant ) ) );
 
393
 
 
394
    if ( !callbackObj.isValid() )
 
395
    {
 
396
        tDebug() << Q_FUNC_INFO << "callback object was not valid, cannot continue";
 
397
        return;
 
398
    }
 
399
 
 
400
    Tomahawk::InfoSystem::InfoPushData pushData = callbackObj.value< Tomahawk::InfoSystem::InfoPushData >();
 
401
 
 
402
    if ( !shortUrl.isEmpty() && longUrl != shortUrl )
 
403
    {
 
404
        QVariantMap flagProps = pushData.infoPair.first;
 
405
        flagProps[ "shorturl" ] = shortUrl;
 
406
        pushData.infoPair.first = flagProps;
 
407
    }
 
408
 
 
409
    tDebug() << Q_FUNC_INFO << "pushInfoPair first is: " << pushData.infoPair.first.keys();
 
410
 
 
411
    QMetaObject::invokeMethod( this, "pushInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPushData, pushData ) );
 
412
}
 
413
 
 
414
 
 
415
void
 
416
InfoSystemWorker::infoSlot( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
 
417
{
 
418
//    qDebug() << Q_FUNC_INFO << "with requestId" << requestId;
 
419
 
 
420
    quint64 requestId = requestData.internalId;
 
421
 
 
422
    if ( m_dataTracker[ requestData.caller ][ requestData.type ] == 0 )
 
423
    {
 
424
//        qDebug() << Q_FUNC_INFO << "Caller was not waiting for that type of data!";
 
425
        return;
 
426
    }
 
427
    if ( !m_requestSatisfiedMap.contains( requestId ) || m_requestSatisfiedMap[ requestId ] )
 
428
    {
 
429
//        qDebug() << Q_FUNC_INFO << "Request was already taken care of!";
 
430
        return;
 
431
    }
 
432
 
 
433
    m_requestSatisfiedMap[ requestId ] = true;
 
434
    emit info( requestData, output );
 
435
 
 
436
    m_dataTracker[ requestData.caller ][ requestData.type ] = m_dataTracker[ requestData.caller ][ requestData.type ] - 1;
 
437
//    qDebug() << "Current count in dataTracker for target" << requestData.caller << "and type" << requestData.type << "is" << m_dataTracker[ requestData.caller ][ requestData.type ];
 
438
    delete m_savedRequestMap[ requestId ];
 
439
    m_savedRequestMap.remove( requestId );
 
440
    checkFinished( requestData );
 
441
}
 
442
 
 
443
 
 
444
void
 
445
InfoSystemWorker::checkFinished( const Tomahawk::InfoSystem::InfoRequestData &requestData )
 
446
{
 
447
    if ( m_dataTracker[ requestData.caller ][ requestData.type ] == 0 )
 
448
        emit finished( requestData.caller, requestData.type );
 
449
 
 
450
    Q_FOREACH( InfoType testtype, m_dataTracker[ requestData.caller ].keys() )
 
451
    {
 
452
        if ( m_dataTracker[ requestData.caller ][ testtype ] != 0 )
 
453
            return;
 
454
    }
 
455
//    qDebug() << "Emitting finished with target" << target;
 
456
    emit finished( requestData.caller );
 
457
}
 
458
 
 
459
 
 
460
void
 
461
InfoSystemWorker::checkTimeoutsTimerFired()
 
462
{
 
463
    qint64 currTime = QDateTime::currentMSecsSinceEpoch();
 
464
    Q_FOREACH( qint64 time, m_timeRequestMapper.keys() )
 
465
    {
 
466
        Q_FOREACH( quint64 requestId, m_timeRequestMapper.values( time ) )
 
467
        {
 
468
            if ( time < currTime )
 
469
            {
 
470
                if ( m_requestSatisfiedMap[ requestId ] )
 
471
                {
 
472
//                    qDebug() << Q_FUNC_INFO << "Removing mapping of" << requestId << "which expired at time" << time << "and was already satisfied";
 
473
                    m_timeRequestMapper.remove( time, requestId );
 
474
                    if ( !m_timeRequestMapper.count( time ) )
 
475
                        m_timeRequestMapper.remove( time );
 
476
                    continue;
 
477
                }
 
478
 
 
479
                //doh, timed out
 
480
//                qDebug() << Q_FUNC_INFO << "Doh, timed out for requestId" << requestId;
 
481
                InfoRequestData *savedData = m_savedRequestMap[ requestId ];
 
482
 
 
483
                InfoRequestData returnData;
 
484
                returnData.caller = savedData->caller;
 
485
                returnData.type = savedData->type;
 
486
                returnData.input = savedData->input;
 
487
                returnData.customData = savedData->customData;
 
488
                emit info( returnData, QVariant() );
 
489
 
 
490
                delete savedData;
 
491
                m_savedRequestMap.remove( requestId );
 
492
 
 
493
                m_dataTracker[ returnData.caller ][ returnData.type ] = m_dataTracker[ returnData.caller ][ returnData.type ] - 1;
 
494
//                qDebug() << "Current count in dataTracker for target" << returnData.caller << "is" << m_dataTracker[ returnData.caller ][ returnData.type ];
 
495
 
 
496
                m_requestSatisfiedMap[ requestId ] = true;
 
497
                m_timeRequestMapper.remove( time, requestId );
 
498
                if ( !m_timeRequestMapper.count( time ) )
 
499
                    m_timeRequestMapper.remove( time );
 
500
 
 
501
                checkFinished( returnData );
 
502
            }
 
503
            else
 
504
            {
 
505
                //we've caught up, the remaining requets still have time to work
 
506
                return;
 
507
            }
 
508
        }
 
509
    }
 
510
}
 
511
 
 
512
 
 
513
} //namespace InfoSystem
 
514
 
 
515
} //namespace Tomahawk