From c56be0b72c9ae9e3b4e81db6ca26cdb0a4a82b1d Mon Sep 17 00:00:00 2001 From: ruglory Date: Mon, 2 Mar 2009 05:27:54 +0000 Subject: [PATCH] Added threading functionality DrivesManager and Drive created git-svn-id: https://svn.code.sf.net/p/qlscribe/svn/trunk@103 cac9541e-1b8d-4bfa-827e-589bba606050 --- lscribed/CMakeLists.txt | 2 +- lscribed/dbuscpp.cpp | 44 ++++++++- lscribed/dbuscpp.h | 25 +++++ lscribed/drivehandler.cpp | 37 ++++--- lscribed/drives.cpp | 192 ++++++++++++++++++++++++++++++++++++ lscribed/drives.h | 77 +++++++++++++++ lscribed/lscribed.h.in | 3 - lscribed/lscribed.pro | 6 +- lscribed/main.cpp | 6 +- lscribed/managerhandler.cpp | 10 +- 10 files changed, 369 insertions(+), 33 deletions(-) create mode 100644 lscribed/drives.cpp create mode 100644 lscribed/drives.h diff --git a/lscribed/CMakeLists.txt b/lscribed/CMakeLists.txt index 8c0b26e..8c76a69 100644 --- a/lscribed/CMakeLists.txt +++ b/lscribed/CMakeLists.txt @@ -30,7 +30,7 @@ IF( CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND CMAKE_COMPILER_IS_GNUCXX ) SET( CMAKE_EXE_LINKER_FLAGS "-m32 -pthread ${CMAKE_EXE_LINKER_FLAGS}" ) ENDIF( CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND CMAKE_COMPILER_IS_GNUCXX ) -SET( LSCRIBED_SRCS main.cpp dbuscpp.cpp managerhandler.cpp drivehandler.cpp +SET( LSCRIBED_SRCS main.cpp dbuscpp.cpp drives.cpp managerhandler.cpp drivehandler.cpp introspecthandler.cpp ) ADD_DEFINITIONS( -Wall ) diff --git a/lscribed/dbuscpp.cpp b/lscribed/dbuscpp.cpp index 877b17d..239cbf8 100644 --- a/lscribed/dbuscpp.cpp +++ b/lscribed/dbuscpp.cpp @@ -113,6 +113,28 @@ void MessageIter::append( const char *str ) dbus_message_iter_append_basic( &m_iter, DBUS_TYPE_STRING, &str ); } +std::string MessageConstIter::signature() const +{ + char *ptr = dbus_message_iter_get_signature( const_cast< DBusMessageIter *>( &m_iter ) ); + std::string rez( ptr ); + dbus_free( ptr ); + return rez; +} + +MessageConstIter MessageConstIter::recurse() const +{ + MessageConstIter rez; + dbus_message_iter_recurse( const_cast< DBusMessageIter *>( &m_iter ), &rez.m_iter ); + return rez; +} + +void *MessageConstIter::getFixedArray( int &elements ) const +{ + void *data =0; + dbus_message_iter_get_fixed_array( const_cast< DBusMessageIter *>( &m_iter ), &data, &elements ); + return data; +} + Message::Message( int type ) { m_message = dbus_message_new( type ); @@ -131,6 +153,11 @@ Message::Message( DBusMessage *msg, bool ownership ) dbus_message_ref( m_message ); } +Message::~Message() +{ + dbus_message_unref( m_message ); +} + Message Message::newMethodReturn() const { return Message( dbus_message_new_method_return( m_message ), true ); @@ -141,6 +168,13 @@ Message Message::newError( const char *error, const char *message ) const return Message( dbus_message_new_error( m_message, error, message ), true ); } +MessageConstIter Message::constIter() const +{ + MessageConstIter rez; + dbus_message_iter_init( m_message, &rez.m_iter ); + return rez; +} + MessageIter Message::appendIter() { MessageIter rez; @@ -158,7 +192,13 @@ const char *Message::path() const return dbus_message_get_path( m_message ); } -Message::~Message() +const char *Message::interface() const { - dbus_message_unref( m_message ); + return dbus_message_get_interface( m_message ); } + +const char *Message::member() const +{ + return dbus_message_get_member( m_message ); +} + diff --git a/lscribed/dbuscpp.h b/lscribed/dbuscpp.h index 8aa7b23..f3a3118 100644 --- a/lscribed/dbuscpp.h +++ b/lscribed/dbuscpp.h @@ -50,6 +50,7 @@ private: class Connection { public: Connection( DBusConnection *conn ); + Connection( const Connection &conn ) : m_connection( conn.m_connection ) {} ~Connection(); dbus_uint32_t send( const Message &msg ); @@ -80,6 +81,27 @@ private: DBusMessageIter *m_container; }; +class MessageConstIter { +public: + MessageConstIter recurse() const; + + std::string signature() const; + bool next() { return dbus_message_iter_next( &m_iter ); } + bool hasNext() const { return dbus_message_iter_has_next( const_cast< DBusMessageIter *>( &m_iter ) ); } + + void *getFixedArray( int &elements ) const; + template T getValue() const + { + T rez = T(); + dbus_message_iter_get_basic( const_cast< DBusMessageIter *>( &m_iter ), &rez ); + return rez; + } + + friend class Message; +private: + DBusMessageIter m_iter; +}; + class Message { public: explicit Message( int type ); @@ -94,11 +116,14 @@ public: bool isMethodCall( const char *interface, const char *method ) const { return dbus_message_is_method_call( m_message, interface, method ); } + MessageConstIter constIter() const; MessageIter appendIter(); void append( const std::string &str ) { append( str.c_str() ); } void append( const char *str ); const char *path() const; + const char *interface() const; + const char *member() const; friend class Connection; private: diff --git a/lscribed/drivehandler.cpp b/lscribed/drivehandler.cpp index 76d029f..830cb97 100644 --- a/lscribed/drivehandler.cpp +++ b/lscribed/drivehandler.cpp @@ -22,13 +22,12 @@ #include -#include "drivehandler.h" #include "lscribed.h" +#include "drivehandler.h" +#include "drives.h" using namespace DBusCpp; -Drives drives; - static const char *strDriveIntrospect = "\ \ @@ -77,12 +76,14 @@ DBusHandlerResult DriveHandler::processMessage( const Message &msg ) if( item[ 0 ] == '/' ) ++item; + DrivesManager &manager = DrivesManager::instance(); + if( msg.isMethodCall( "org.freedesktop.DBus.Introspectable", "Introspect" ) ) { std::string introspect = generateInrospectHeader(); if( strcmp( item, "drives" ) == 0 ) { - for( Drives::const_iterator it = drives.begin(); it != drives.end(); ++it ) - introspect += "first + "\"/>"; + for( DrivesManager::const_iterator it = manager.begin(); it != manager.end(); ++it ) + introspect += "path() + "\"/>"; } else introspect += strDriveIntrospect; @@ -94,23 +95,21 @@ DBusHandlerResult DriveHandler::processMessage( const Message &msg ) return rez = DBUS_HANDLER_RESULT_HANDLED; } - Drives::const_iterator f = drives.find( item ); - if( f == drives.end() ) + const char *interface = msg.interface(); + if( !interface || strcmp( interface, "org.lightscribe.drive" ) ) + return rez; + + const char *member = msg.member(); + if( !member ) + return rez; + + DrivesManager::const_iterator f = manager.find( item ); + if( f == manager.end() ) return rez; rez = DBUS_HANDLER_RESULT_HANDLED; - std::cout << "calling method on item " << item << std::endl; - if( msg.isMethodCall( "org.lightscribe.drive", "name" ) ) { - Message reply = msg.newMethodReturn(); - reply.append( f->second ); - connection()->send( reply ); - return rez; - } - if( msg.isMethodCall( "org.lightscribe.drive", "preview" ) ) { - return rez; - } - Message reply = msg.newError( DBUS_ERROR_NOT_SUPPORTED, "method is not supported" ); - connection()->send( reply ); + std::cout << "calling method " << member << " on item " << item << std::endl; + (*f)->invoke( member, msg ); return rez; } diff --git a/lscribed/drives.cpp b/lscribed/drives.cpp new file mode 100644 index 0000000..a71ee4a --- /dev/null +++ b/lscribed/drives.cpp @@ -0,0 +1,192 @@ +/* qlscribe - Qt based application to print lightScribe discs + + Copyright (C) 2009 Vyacheslav Kononenko + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + $Id$ */ + +#include "drives.h" + +#include +#include +#include + +using namespace LightScribe; + +Drive::Drive( int index, const std::string &path, const std::string &name ) + : m_index( index ), m_path( path ), m_name( name ), m_threadStarted( false ), m_message( 0 ) +{ +} + +Drive::~Drive() +{ + if( m_threadStarted ) { + pthread_cancel( m_thread ); + pthread_join( m_thread, 0 ); + pthread_cond_destroy( &m_cond ); + } +} + +void *routine( void *ptr ) +{ + reinterpret_cast< Drive * >( ptr )->routine(); + return ptr; +} + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +void Drive::invoke( const std::string &method, const DBusCpp::Message &msg ) +{ + DrivesManager &man = DrivesManager::instance(); + if( method == "name" ) { + DBusCpp::Message reply = msg.newMethodReturn(); + reply.append( name() ); + man.connection().send( reply ); + return; + } + if( method == "preview" || method == "print" ) { + if( !m_threadStarted ) { + m_threadStarted = true; + pthread_cond_init( &m_cond, 0 ); + pthread_create( &m_thread, 0, ::routine, this ); + } + pthread_mutex_lock( &mutex ); + if( m_message ) { + DBusCpp::Message reply = msg.newError( DBUS_ERROR_FAILED, "drive is busy, try again later" ); + man.connection().send( reply ); + } + m_message = new DBusCpp::Message( msg ); + pthread_cond_signal( &m_cond ); + pthread_mutex_unlock( &mutex ); + return; + } + DBusCpp::Message reply = msg.newError( DBUS_ERROR_UNKNOWN_METHOD, "method is not supported" ); + man.connection().send( reply ); +} + +void Drive::routine() +{ + DrivesManager &man = DrivesManager::instance(); + + bool first = true; + while( true ) { + pthread_mutex_lock( &mutex ); + + if( first ) + first = false; + else { + delete m_message; + m_message = 0; + } + while( !m_message ) + pthread_cond_wait( &m_cond, &mutex ); + + pthread_mutex_unlock( &mutex ); + + LS_LabelMode mode; + LS_DrawOptions options; + LS_PrintQuality quality; + LS_MediaOptimizationLevel level; + + char *image = 0; + int imageSize = 0; + try { + DBusCpp::MessageConstIter iter = m_message->constIter(); + if( iter.signature() != "(iiii)" ) + throw std::string( "invalid argument for params: " ) + iter.signature() + ", (iiii) expected"; + + DBusCpp::MessageConstIter sub = iter.recurse(); + + mode = LS_LabelMode( sub.getValue() ); sub.next(); + options = LS_DrawOptions( sub.getValue() ); sub.next(); + quality = LS_PrintQuality( sub.getValue() ); sub.next(); + level = LS_MediaOptimizationLevel( sub.getValue() ); sub.next(); + + std::cout << "got parameters " << std::endl; + + if( !iter.next() ) + throw std::string( "image argument missing" ); + + if( iter.signature() != "ay" ) + throw std::string( "invalid argument for image: " ) + iter.signature() + ", ay expected"; + + sub = iter.recurse(); + + image = reinterpret_cast< char * >( sub.getFixedArray( imageSize ) ); + } + catch( const std::string &str ) { + std::cout << "exception " << str << std::endl; + DBusCpp::Message reply = m_message->newError( DBUS_ERROR_INVALID_ARGS, str.c_str() ); + man.connection().send( reply ); + continue; + } + { + std::ofstream out( "/tmp/image.bmp" ); + out.write( image, imageSize ); + } + DBusCpp::Message reply = m_message->newMethodReturn(); + reply.append( "/tmp/image.bmp" ); + man.connection().send( reply ); + } +} + +DrivesManager::DrivesManager() + : m_connection( 0 ) +{ +} + +void DrivesManager::init( DBusCpp::Connection conn ) +{ + m_connection = conn; + + DiscPrintMgr manager; + EnumDiscPrinters printers = manager.EnumDiscPrinters(); + const unsigned count = printers.Count(); + for( unsigned i = 0; i < count; ++i ) { + DiscPrinter printer = printers.Item( i ); + + char path[ 10 ]; + sprintf( path, "drive%d", i ); + m_drives.push_back( new Drive( i, path, printer.GetPrinterDisplayName() ) ); + } +} + + +DrivesManager::~DrivesManager() +{ + for( const_iterator f = begin(); f != end(); ++f ) + delete *f; +} + +DrivesManager &DrivesManager::instance() +{ + static DrivesManager theManager; + return theManager; + +} + +DrivesManager::const_iterator DrivesManager::find( const std::string &path ) const +{ + const_iterator f; + for( f = begin(); f != end(); ++f ) + if( (*f)->path() == path ) + break; + + return f; +} + + + diff --git a/lscribed/drives.h b/lscribed/drives.h new file mode 100644 index 0000000..31bac69 --- /dev/null +++ b/lscribed/drives.h @@ -0,0 +1,77 @@ +/* qlscribe - Qt based application to print lightScribe discs + + Copyright (C) 2009 Vyacheslav Kononenko + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + $Id$ */ + +#ifndef DRIVES_H +#define DRIVES_H + +#include +#include + +#include "dbuscpp.h" + +class Drive { +public: + const std::string &path() const { return m_path; } + const std::string &name() const { return m_name; } + + void invoke( const std::string &method, const DBusCpp::Message &msg ); + + friend class DrivesManager; + friend void *routine( void * ); + +private: + Drive( int index, const std::string &path, const std::string &name ); + ~Drive(); + + void routine(); + + int m_index; + std::string m_path; + std::string m_name; + bool m_threadStarted; + pthread_t m_thread; + pthread_cond_t m_cond; + DBusCpp::Message *m_message; +}; + +class DrivesManager { +public: + typedef std::vector< Drive * > Drives; + typedef Drives::const_iterator const_iterator; + + static DrivesManager &instance(); + + void init( DBusCpp::Connection conn ); + + const_iterator begin() const { return m_drives.begin(); } + const_iterator end() const { return m_drives.end(); } + const_iterator find( const std::string &path ) const; + + DBusCpp::Connection connection() const { return m_connection; } + +private: + DrivesManager(); + ~DrivesManager(); + + Drives m_drives; + DBusCpp::Connection m_connection; +}; + +#endif // DRIVES_H diff --git a/lscribed/lscribed.h.in b/lscribed/lscribed.h.in index 92d3823..74fa1bd 100644 --- a/lscribed/lscribed.h.in +++ b/lscribed/lscribed.h.in @@ -24,9 +24,6 @@ #include #include -typedef std::map< std::string, std::string > Drives; -extern Drives drives; - const char * const DBusServiceName = "@QLSCRIBE_DBUS_SERVICE@"; const char * const DBusManagerPath = "@QLSCRIBE_DBUS_MANAGER@"; const char * const DBusDrivesPath = "@QLSCRIBE_DBUS_DRIVES@"; diff --git a/lscribed/lscribed.pro b/lscribed/lscribed.pro index e784e8f..24f2ae7 100644 --- a/lscribed/lscribed.pro +++ b/lscribed/lscribed.pro @@ -11,8 +11,10 @@ SOURCES += main.cpp \ dbuscpp.cpp \ managerhandler.cpp \ drivehandler.cpp \ - introspecthandler.cpp + introspecthandler.cpp \ + drives.cpp HEADERS += dbuscpp.h \ drivehandler.h \ managerhandler.h \ - introspecthandler.h + introspecthandler.h \ + drives.h diff --git a/lscribed/main.cpp b/lscribed/main.cpp index 2ccfbcf..23a0a9a 100644 --- a/lscribed/main.cpp +++ b/lscribed/main.cpp @@ -26,9 +26,12 @@ #include "introspecthandler.h" #include "managerhandler.h" #include "drivehandler.h" +#include "drives.h" int main( int argc, char **argv ) { + dbus_threads_init_default(); + DBusError err; dbus_error_init( &err ); @@ -53,8 +56,7 @@ int main( int argc, char **argv ) conn.registerHandler( DBusManagerPath, new DBusCpp::ManagerHandler, false ); conn.registerHandler( DBusDrivesPath, new DBusCpp::DriveHandler, true ); - drives.insert( std::make_pair( "drive0", "DRIVE 0" ) ); - drives.insert( std::make_pair( "drive1", "DRIVE 1" ) ); + DrivesManager::instance().init( conn ); while( dbus_connection_read_write_dispatch( conn.ptr(), -1 ) ); diff --git a/lscribed/managerhandler.cpp b/lscribed/managerhandler.cpp index 051ea8e..ff2cdd3 100644 --- a/lscribed/managerhandler.cpp +++ b/lscribed/managerhandler.cpp @@ -18,8 +18,9 @@ $Id$ */ -#include "managerhandler.h" #include "lscribed.h" +#include "managerhandler.h" +#include "drives.h" using namespace DBusCpp; @@ -53,11 +54,12 @@ DBusHandlerResult ManagerHandler::processMessage( const Message &msg ) { MessageIter sub = args.openContainer( DBUS_TYPE_ARRAY, "{ss}" ); - for( Drives::const_iterator it = drives.begin(); it != drives.end(); ++it ) { + DrivesManager &manager = DrivesManager::instance(); + for( DrivesManager::const_iterator it = manager.begin(); it != manager.end(); ++it ) { MessageIter itemIterator = sub.openContainer( DBUS_TYPE_DICT_ENTRY, 0 ); - itemIterator.append( std::string( DBusDrivesPath ) + "/" + it->first ); - itemIterator.append( it->second ); + itemIterator.append( std::string( DBusDrivesPath ) + "/" + (*it)->path() ); + itemIterator.append( (*it)->name() ); } }