mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Make viewer run in separate process. Should fix #533
This commit is contained in:
parent
6cf529b5da
commit
4ba916c130
@ -12,7 +12,7 @@
|
||||
## 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.Warning
|
||||
import os, sys, textwrap, cStringIO, collections, traceback, shutil
|
||||
import os, sys, textwrap, collections, traceback, shutil, time
|
||||
|
||||
from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \
|
||||
QSettings, QVariant, QSize, QThread, QString
|
||||
@ -46,8 +46,6 @@ from libprs500.gui2.dialogs.lrf_single import LRFSingleDialog, LRFBulkDialog
|
||||
from libprs500.gui2.dialogs.config import ConfigDialog
|
||||
from libprs500.gui2.dialogs.search import SearchDialog
|
||||
from libprs500.gui2.dialogs.user_profiles import UserProfiles
|
||||
from libprs500.gui2.lrf_renderer.main import file_renderer
|
||||
from libprs500.gui2.lrf_renderer.main import option_parser as lrfviewerop
|
||||
from libprs500.library.database import DatabaseLocked
|
||||
from libprs500.ebooks.metadata.meta import set_metadata
|
||||
from libprs500.ebooks.metadata import MetaInformation
|
||||
@ -80,6 +78,7 @@ class Main(MainWindow, Ui_MainWindow):
|
||||
self.delete_memory = {}
|
||||
self.conversion_jobs = {}
|
||||
self.persistent_files = []
|
||||
self.viewer_job_id = 1
|
||||
self.default_thumbnail = None
|
||||
self.device_error_dialog = ConversionErrorDialog(self, _('Error communicating with device'), ' ')
|
||||
self.device_error_dialog.setModal(Qt.NonModal)
|
||||
@ -745,23 +744,21 @@ class Main(MainWindow, Ui_MainWindow):
|
||||
title = self.library_view.model().db.title(row)
|
||||
id = self.library_view.model().db.id(row)
|
||||
if 'LRF' not in formats.upper():
|
||||
d = error_dialog(self, _('Cannot view'), _('%s is not available in LRF format. Please convert it first.')%(title,))
|
||||
d = error_dialog(self, _('Cannot view'),
|
||||
_('%s is not available in LRF format. Please convert it first.')%(title,))
|
||||
d.exec_()
|
||||
return
|
||||
|
||||
data = cStringIO.StringIO(self.library_view.model().db.format(row, 'LRF'))
|
||||
parser = lrfviewerop()
|
||||
opts = parser.parse_args(['lrfviewer'])[0]
|
||||
|
||||
viewer = file_renderer(data, opts)
|
||||
viewer.libprs500_db_id = id
|
||||
viewer.show()
|
||||
viewer.render()
|
||||
self.viewers.append(viewer)
|
||||
QObject.connect(viewer, SIGNAL('viewer_closed(PyQt_PyObject)'), self.viewer_closed)
|
||||
|
||||
def viewer_closed(self, viewer):
|
||||
self.viewers.remove(viewer)
|
||||
pt = PersistentTemporaryFile('_viewer')
|
||||
pt.write(self.library_view.model().db.format(row, 'LRF'))
|
||||
pt.close()
|
||||
self.persistent_files.append(pt)
|
||||
args = ['lrfviewer', pt.name]
|
||||
self.job_manager.process_server.run('viewer%d'%self.viewer_job_id,
|
||||
'lrfviewer', kwdargs=dict(args=args),
|
||||
monitor=False)
|
||||
self.viewer_job_id += 1
|
||||
time.sleep(2) # User feedback
|
||||
|
||||
############################################################################
|
||||
|
||||
|
@ -19,11 +19,13 @@ import re, sys, tempfile, os, subprocess, cPickle, cStringIO, traceback, atexit,
|
||||
from functools import partial
|
||||
from libprs500.ebooks.lrf.any.convert_from import main as any2lrf
|
||||
from libprs500.ebooks.lrf.web.convert_from import main as web2lrf
|
||||
from libprs500.gui2.lrf_renderer.main import main as lrfviewer
|
||||
from libprs500 import iswindows
|
||||
|
||||
PARALLEL_FUNCS = {
|
||||
'any2lrf' : partial(any2lrf, gui_mode=True),
|
||||
'web2lrf' : web2lrf,
|
||||
'lrfviewer' : lrfviewer,
|
||||
}
|
||||
Popen = subprocess.Popen
|
||||
|
||||
@ -50,11 +52,21 @@ class Server(object):
|
||||
atexit.register(cleanup, self.tdir)
|
||||
self.stdout = {}
|
||||
|
||||
def run(self, job_id, func, args=(), kwdargs={}):
|
||||
def run(self, job_id, func, args=[], kwdargs={}, monitor=True):
|
||||
'''
|
||||
Run a job in a separate process.
|
||||
@param job_id: A unique (per server) identifier
|
||||
@param func: One of C{PARALLEL_FUNCS.keys()}
|
||||
@param args: A list of arguments to pass of C{func}
|
||||
@param kwdargs: A dictionary of keyword arguments to pass to C{func}
|
||||
@param monitor: If False launch the child process and return. Do not monitor/communicate with it.
|
||||
@return: (result, exception, formatted_traceback, log) where log is the combined
|
||||
stdout + stderr of the child process; or None if monitor is True.
|
||||
'''
|
||||
job_id = str(job_id)
|
||||
job_dir = os.path.join(self.tdir, job_id)
|
||||
if os.path.exists(job_dir):
|
||||
raise ValueError('Cannot run job. The job_id %s has already been used.')
|
||||
raise ValueError('Cannot run job. The job_id %s has already been used.'%job_id)
|
||||
os.mkdir(job_dir)
|
||||
self.stdout[job_id] = cStringIO.StringIO()
|
||||
|
||||
@ -68,7 +80,11 @@ class Server(object):
|
||||
os.environ['PATH'] += ':'+fd
|
||||
cmd = prefix + 'from libprs500.parallel import run_job; run_job(\'%s\')'%binascii.hexlify(job_data)
|
||||
|
||||
if monitor:
|
||||
p = Popen((python, '-c', cmd), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
else:
|
||||
Popen((python, '-c', cmd))
|
||||
return
|
||||
while p.returncode is None:
|
||||
self.stdout[job_id].write(p.stdout.readline())
|
||||
p.poll()
|
||||
@ -77,7 +93,8 @@ class Server(object):
|
||||
|
||||
job_result = os.path.join(job_dir, 'job_result.pickle')
|
||||
if not os.path.exists(job_result):
|
||||
result, exception, traceback = None, ('ParallelRuntimeError', 'The worker process died unexpectedly.'), ''
|
||||
result, exception, traceback = None, ('ParallelRuntimeError',
|
||||
'The worker process died unexpectedly.'), ''
|
||||
else:
|
||||
result, exception, traceback = cPickle.load(open(job_result, 'rb'))
|
||||
log = self.stdout[job_id].getvalue()
|
||||
@ -98,6 +115,7 @@ def run_job(job_data):
|
||||
exception = (err.__class__.__name__, unicode(str(err), 'utf-8', 'replace'))
|
||||
tb = traceback.format_exc()
|
||||
|
||||
if os.path.exists(os.path.dirname(job_result)):
|
||||
cPickle.dump((result, exception, tb), open(job_result, 'wb'))
|
||||
|
||||
def main():
|
||||
|
Loading…
x
Reference in New Issue
Block a user