WIP. Using WIOService to handle Services

This commit is contained in:
emeric
2014-08-05 13:11:31 +02:00
parent f26e6cad7c
commit 9fdc9f41dd
12 changed files with 148 additions and 65 deletions
+1
View File
@@ -2,6 +2,7 @@
[ServiceManager] [ServiceManager]
- Rework the whole start/stop/try/cach/thread/interrupts things - Rework the whole start/stop/try/cach/thread/interrupts things
- Rework the io_service thread pool thing - Rework the io_service thread pool thing
- Use our own WIOService
[Services] [Services]
- [UI] generate argc/argv from a config file (crypto, port info, db path) - [UI] generate argc/argv from a config file (crypto, port info, db path)
+93 -17
View File
@@ -2,6 +2,7 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <boost/asio/placeholders.hpp>
#include "database/MediaDirectory.hpp" #include "database/MediaDirectory.hpp"
#include "database/AudioTypes.hpp" #include "database/AudioTypes.hpp"
@@ -14,46 +15,114 @@ namespace DatabaseUpdater {
using namespace Database; using namespace Database;
Updater::Updater(boost::filesystem::path dbPath, MetaData::Parser& parser) Updater::Updater(boost::filesystem::path dbPath, MetaData::Parser& parser)
: _db(dbPath), : _running(false),
_scheduleTimer(_ioService),
_db(dbPath),
_metadataParser(parser) _metadataParser(parser)
{ {
_ioService.setThreadCount(1);
} }
void void
Updater::process(void) Updater::start(void)
{
_running = true;
// post some jobs in the io_service
processNextJob();
_ioService.start();
}
void
Updater::stop(void)
{
_running = false;
// TODO cancel all jobs (timer, ...)
_scheduleTimer.cancel();
_ioService.stop();
}
void
Updater::processNextJob(void)
{
Wt::Dbo::Transaction transaction(_db.getSession());
MediaDirectorySettings::pointer settings = MediaDirectorySettings::get(_db.getSession());
if (settings->getManualScanRequested())
{
settings.modify()->setManualScanRequested(false);
// Schedule immediate scan
scheduleScan( boost::posix_time::seconds(0) );
}
else
{
// boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
// TODO
}
}
void
Updater::scheduleScan( boost::posix_time::time_duration duration)
{
std::cout << "Scheduling next scan in " << duration << std::endl;
_scheduleTimer.expires_from_now(duration);
_scheduleTimer.async_wait( boost::bind( &Updater::process, this, boost::asio::placeholders::error) );
}
void
Updater::scheduleScan( boost::posix_time::ptime time)
{
_scheduleTimer.expires_at(time);
_scheduleTimer.async_wait( boost::bind( &Updater::process, this, boost::asio::placeholders::error) );
}
void
Updater::process(boost::system::error_code err)
{
if (!err)
{ {
removeMissingAudioFiles(_result.audioStats); removeMissingAudioFiles(_result.audioStats);
// TODO video files // TODO video files
Wt::Dbo::Transaction transaction(_db.getSession()); std::vector<boost::filesystem::path> pathes;
std::vector<MediaDirectory::pointer> mediaDirectories = MediaDirectory::getAll(_db.getSession());
BOOST_FOREACH( MediaDirectory::pointer directory, mediaDirectories)
{ {
switch (directory->getType()) { Wt::Dbo::Transaction transaction(_db.getSession());
case MediaDirectory::Audio: std::vector<MediaDirectory::pointer> mediaDirectories = MediaDirectory::getAll(_db.getSession());
refreshAudioDirectory(directory->getPath(), _result.audioStats); BOOST_FOREACH(MediaDirectory::pointer directory, mediaDirectories)
break; pathes.push_back(directory->getPath());
case MediaDirectory::Video:
refreshVideoDirectory(directory->getPath());
break;
}
} }
BOOST_FOREACH( boost::filesystem::path p, pathes)
refreshAudioDirectory(p, _result.audioStats);
std::cout << "Audio changes = " << _result.audioStats.nbChanges() << std::endl; std::cout << "Audio changes = " << _result.audioStats.nbChanges() << std::endl;
std::cout << "Video changes = " << _result.videoStats.nbChanges() << std::endl; std::cout << "Video changes = " << _result.videoStats.nbChanges() << std::endl;
Database::MediaDirectorySettings::pointer settings = Database::MediaDirectorySettings::get(_db.getSession()); // Update database stats only if it has not been interrupted
if (_running)
{
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
{
Wt::Dbo::Transaction transaction(_db.getSession());
Database::MediaDirectorySettings::pointer settings = Database::MediaDirectorySettings::get(_db.getSession());
if (_result.audioStats.nbChanges() + _result.videoStats.nbChanges() > 0) if (_result.audioStats.nbChanges() + _result.videoStats.nbChanges() > 0)
settings.modify()->setLastUpdate(now); settings.modify()->setLastUpdate(now);
settings.modify()->setLastScan(now); settings.modify()->setLastScan(now);
}
transaction.commit(); processNextJob();
}
}
} }
void void
@@ -232,6 +301,12 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
void void
Updater::refreshAudioDirectory( const boost::filesystem::path& p, Stats& stats) Updater::refreshAudioDirectory( const boost::filesystem::path& p, Stats& stats)
{ {
if (!_running)
{
std::cerr << "Not running! Stopping scan" << std::endl;
return;
}
if (boost::filesystem::exists(p) && boost::filesystem::is_directory(p)) { if (boost::filesystem::exists(p) && boost::filesystem::is_directory(p)) {
typedef std::vector<boost::filesystem::path> Paths; // store paths, typedef std::vector<boost::filesystem::path> Paths; // store paths,
@@ -247,6 +322,7 @@ Updater::refreshAudioDirectory( const boost::filesystem::path& p, Stats& stats)
if (boost::filesystem::is_directory(file)) { if (boost::filesystem::is_directory(file)) {
refreshAudioDirectory( file, stats ); refreshAudioDirectory( file, stats );
} }
else if (boost::filesystem::is_regular(file)) { else if (boost::filesystem::is_regular(file)) {
processAudioFile( file, stats ); processAudioFile( file, stats );
} }
+18 -2
View File
@@ -1,6 +1,8 @@
#ifndef DB_UPDATER_UPDATER_HPP #ifndef DB_UPDATER_UPDATER_HPP
#define DB_UPDATER_UPDATER_HPP #define DB_UPDATER_UPDATER_HPP
#include <boost/asio/deadline_timer.hpp>
#include <Wt/WIOService>
#include "metadata/MetaData.hpp" #include "metadata/MetaData.hpp"
#include "database/DatabaseHandler.hpp" #include "database/DatabaseHandler.hpp"
@@ -15,8 +17,9 @@ class Updater
public: public:
Updater(boost::filesystem::path db, MetaData::Parser& parser); Updater(boost::filesystem::path db, MetaData::Parser& parser);
// Update database void start();
void process(); void stop();
private: private:
@@ -36,6 +39,14 @@ class Updater
Stats videoStats; Stats videoStats;
}; };
// Job handling
void processNextJob();
void scheduleScan(boost::posix_time::time_duration duration);
void scheduleScan(boost::posix_time::ptime time);
// Update database
void process(boost::system::error_code ec);
// Video // Video
void refreshVideoDirectory( const boost::filesystem::path& directory ); void refreshVideoDirectory( const boost::filesystem::path& directory );
void processVideoFile( const boost::filesystem::path& file); void processVideoFile( const boost::filesystem::path& file);
@@ -47,6 +58,11 @@ class Updater
Database::Path::pointer getAddPath(const boost::filesystem::path& path); Database::Path::pointer getAddPath(const boost::filesystem::path& path);
bool _running;
Wt::WIOService _ioService;
boost::asio::deadline_timer _scheduleTimer;
Database::Handler _db; Database::Handler _db;
MetaData::Parser& _metadataParser; MetaData::Parser& _metadataParser;
+2 -2
View File
@@ -34,8 +34,8 @@ int main(int argc, char* argv[])
std::cout << "Starting services..." << std::endl; std::cout << "Starting services..." << std::endl;
serviceManager.startService( std::make_shared<DatabaseUpdateService>( serviceManager.getIoService(), dbPath) ); serviceManager.startService( std::make_shared<DatabaseUpdateService>( dbPath) );
serviceManager.startService( std::make_shared<RemoteServerService>( serviceManager.getIoService(), remoteListenEndpoint, dbPath) ); serviceManager.startService( std::make_shared<RemoteServerService>( remoteListenEndpoint, dbPath) );
serviceManager.startService( std::make_shared<UserInterfaceService>(argc, argv, dbPath) ); serviceManager.startService( std::make_shared<UserInterfaceService>(argc, argv, dbPath) );
std::cout << "Running..." << std::endl; std::cout << "Running..." << std::endl;
+8 -3
View File
@@ -9,14 +9,15 @@
namespace Remote { namespace Remote {
namespace Server { namespace Server {
Server::Server(boost::asio::io_service& ioService, const endpoint_type& bindEndpoint, boost::filesystem::path dbPath) Server::Server(const endpoint_type& bindEndpoint, boost::filesystem::path dbPath)
: :
_ioService(ioService),
_acceptor(_ioService, bindEndpoint, true /*SO_REUSEADDR*/), _acceptor(_ioService, bindEndpoint, true /*SO_REUSEADDR*/),
_connectionManager(), _connectionManager(),
_context(boost::asio::ssl::context::tlsv1_server), _context(boost::asio::ssl::context::tlsv1_server),
_dbPath(dbPath) _dbPath(dbPath)
{ {
_ioService.setThreadCount(1);
_context.set_options( boost::asio::ssl::context::default_workarounds // TODO check this thing _context.set_options( boost::asio::ssl::context::default_workarounds // TODO check this thing
| boost::asio::ssl::context::single_dh_use | boost::asio::ssl::context::single_dh_use
| boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::no_sslv2
@@ -29,12 +30,14 @@ _dbPath(dbPath)
} }
void void
Server::run() Server::start()
{ {
// While the server is running, there is always at least one // While the server is running, there is always at least one
// asynchronous operation outstanding: the asynchronous accept call waiting // asynchronous operation outstanding: the asynchronous accept call waiting
// for new incoming connections. // for new incoming connections.
asyncAccept(); asyncAccept();
_ioService.start();
} }
void void
@@ -77,6 +80,8 @@ Server::stop()
// operations. // operations.
_acceptor.close(); _acceptor.close();
_connectionManager.stopAll(); _connectionManager.stopAll();
_ioService.stop();
} }
} // namespace Server } // namespace Server
+5 -3
View File
@@ -1,6 +1,8 @@
#ifndef REMOTE_SERVER_HPP #ifndef REMOTE_SERVER_HPP
#define REMOTE_SERVER_HPP #define REMOTE_SERVER_HPP
#include <Wt/WIOService>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
@@ -24,10 +26,10 @@ class Server
typedef boost::asio::ip::tcp::endpoint endpoint_type; typedef boost::asio::ip::tcp::endpoint endpoint_type;
// Serve up data from the given database // Serve up data from the given database
Server(boost::asio::io_service& ioService, const endpoint_type& bindEndpoint, boost::filesystem::path dbPath); Server(const endpoint_type& bindEndpoint, boost::filesystem::path dbPath);
// Run the server's io_service loop. // Run the server's io_service loop.
void run(); void start();
void stop(); void stop();
@@ -36,7 +38,7 @@ class Server
void asyncAccept(); void asyncAccept();
void handleAccept(std::shared_ptr<Connection> newConnection, boost::system::error_code ec); void handleAccept(std::shared_ptr<Connection> newConnection, boost::system::error_code ec);
boost::asio::io_service& _ioService; Wt::WIOService _ioService;
/// Acceptor used to listen for incoming connections. /// Acceptor used to listen for incoming connections.
boost::asio::ip::tcp::acceptor _acceptor; boost::asio::ip::tcp::acceptor _acceptor;
+3 -15
View File
@@ -2,7 +2,7 @@
#include "DatabaseUpdateService.hpp" #include "DatabaseUpdateService.hpp"
DatabaseUpdateService::DatabaseUpdateService(boost::asio::io_service& ioService, const boost::filesystem::path& p) DatabaseUpdateService::DatabaseUpdateService(const boost::filesystem::path& p)
: _metadataParser(), : _metadataParser(),
_databaseUpdater( p, _metadataParser) _databaseUpdater( p, _metadataParser)
{ {
@@ -11,18 +11,14 @@ DatabaseUpdateService::DatabaseUpdateService(boost::asio::io_service& ioService,
void void
DatabaseUpdateService::start(void) DatabaseUpdateService::start(void)
{ {
// TODO _databaseUpdater.start();
// Read database parameters and program a timer for the next scan
// _thread = boost::thread(boost::bind(&DatabaseUpdater::Updater::process, &_databaseUpdater));
} }
void void
DatabaseUpdateService::stop(void) DatabaseUpdateService::stop(void)
{ {
std::cout << "DatabaseUpdateService::stop, processing..." << std::endl; std::cout << "DatabaseUpdateService::stop, processing..." << std::endl;
// no effect if thread does not exist _databaseUpdater.stop();
_thread.interrupt();
_thread.join();
std::cout << "DatabaseUpdateService::stop, process done" << std::endl; std::cout << "DatabaseUpdateService::stop, process done" << std::endl;
} }
@@ -34,11 +30,3 @@ DatabaseUpdateService::restart(void)
start(); start();
} }
bool
DatabaseUpdateService::isScanning(void) const
{
// scanning is active only if a thread is running the updater
return _thread.get_id() != boost::thread::id();
}
+1 -6
View File
@@ -15,20 +15,15 @@ class DatabaseUpdateService : public Service
typedef std::shared_ptr<DatabaseUpdateService> pointer; typedef std::shared_ptr<DatabaseUpdateService> pointer;
DatabaseUpdateService(boost::asio::io_service& ioService, const boost::filesystem::path& p); DatabaseUpdateService(const boost::filesystem::path& p);
// Service interface // Service interface
void start(void); void start(void);
void stop(void); void stop(void);
void restart(void); void restart(void);
// Specific interface
bool isScanning(void) const; //return if the service is currently scanning the db
private: private:
boost::thread _thread;
MetaData::AvFormat _metadataParser; MetaData::AvFormat _metadataParser;
DatabaseUpdater::Updater _databaseUpdater; // Todo use handler DatabaseUpdater::Updater _databaseUpdater; // Todo use handler
}; };
+5 -3
View File
@@ -1,8 +1,8 @@
#include "RemoteServerService.hpp" #include "RemoteServerService.hpp"
RemoteServerService::RemoteServerService(boost::asio::io_service& ioService, const Remote::Server::Server::endpoint_type& endpoint, boost::filesystem::path dbPath) RemoteServerService::RemoteServerService(const Remote::Server::Server::endpoint_type& endpoint, boost::filesystem::path dbPath)
: _server(ioService, endpoint, dbPath) : _server(endpoint, dbPath)
{ {
} }
@@ -10,7 +10,8 @@ void
RemoteServerService::start(void) RemoteServerService::start(void)
{ {
std::cout << "RemoteServerService::start, starting..." << std::endl; std::cout << "RemoteServerService::start, starting..." << std::endl;
_server.run(); _server.start();
std::cout << "RemoteServerService::start, started!" << std::endl;
} }
@@ -19,6 +20,7 @@ RemoteServerService::stop(void)
{ {
std::cout << "RemoteServerService::stop, stopping..." << std::endl; std::cout << "RemoteServerService::stop, stopping..." << std::endl;
_server.stop(); _server.stop();
std::cout << "RemoteServerService::stop, stopped!" << std::endl;
} }
void void
+1 -1
View File
@@ -11,7 +11,7 @@ class RemoteServerService : public Service
{ {
public: public:
RemoteServerService(boost::asio::io_service& ioService, const Remote::Server::Server::endpoint_type& endpoint, boost::filesystem::path dbPath); RemoteServerService(const Remote::Server::Server::endpoint_type& endpoint, boost::filesystem::path dbPath);
void start(void); void start(void);
void stop(void); void stop(void);
+3 -2
View File
@@ -27,7 +27,6 @@ ServiceManager::ServiceManager()
ServiceManager::~ServiceManager() ServiceManager::~ServiceManager()
{ {
stopServices();
} }
void void
@@ -44,9 +43,11 @@ ServiceManager::run()
catch( std::exception& e ) catch( std::exception& e )
{ {
std::cerr << "Caugh exception in service : " << e.what() << std::endl; std::cerr << "Caugh exception in service : " << e.what() << std::endl;
stopServices();
} }
// Stopping services
stopServices();
std::cout << "ServiceManager::run complete!" << std::endl; std::cout << "ServiceManager::run complete!" << std::endl;
} }
-3
View File
@@ -22,9 +22,6 @@ class ServiceManager
// Return in case of failure/stop by user // Return in case of failure/stop by user
void run(); void run();
boost::asio::io_service& getIoService() {return _ioService;}
const boost::asio::io_service& getIoService() const {return _ioService;}
template <class T> typename T::pointer getService(); template <class T> typename T::pointer getService();
boost::mutex& mutex() { return _mutex;} boost::mutex& mutex() { return _mutex;}