mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Content server: Allow running of content server as a WSGI application within another server. Add tutorial for this to the User Manual.
This commit is contained in:
parent
3da2ef7230
commit
89e7c15ea5
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
''' Code to manage ebook library'''
|
||||
|
||||
def db():
|
||||
def db(path=None):
|
||||
from calibre.library.database2 import LibraryDatabase2
|
||||
from calibre.utils.config import prefs
|
||||
return LibraryDatabase2(prefs['library_path'])
|
||||
return LibraryDatabase2(path if path else prefs['library_path'])
|
||||
|
@ -28,11 +28,13 @@ from calibre.library.server.browse import BrowseServer
|
||||
|
||||
class DispatchController(object): # {{{
|
||||
|
||||
def __init__(self, prefix):
|
||||
def __init__(self, prefix, wsgi=False):
|
||||
self.dispatcher = cherrypy.dispatch.RoutesDispatcher()
|
||||
self.funcs = []
|
||||
self.seen = set([])
|
||||
self.prefix = prefix if prefix else ''
|
||||
if wsgi:
|
||||
self.prefix = ''
|
||||
|
||||
def __call__(self, name, route, func, **kwargs):
|
||||
if name in self.seen:
|
||||
@ -96,7 +98,9 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
|
||||
|
||||
server_name = __appname__ + '/' + __version__
|
||||
|
||||
def __init__(self, db, opts, embedded=False, show_tracebacks=True):
|
||||
def __init__(self, db, opts, embedded=False, show_tracebacks=True,
|
||||
wsgi=False):
|
||||
self.is_wsgi = bool(wsgi)
|
||||
self.opts = opts
|
||||
self.embedded = embedded
|
||||
self.state_callback = None
|
||||
@ -124,25 +128,36 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
|
||||
'server.socket_timeout' : opts.timeout, #seconds
|
||||
'server.thread_pool' : opts.thread_pool, # number of threads
|
||||
})
|
||||
if embedded:
|
||||
if embedded or wsgi:
|
||||
cherrypy.config.update({'engine.SIGHUP' : None,
|
||||
'engine.SIGTERM' : None,})
|
||||
self.config = {'global': {
|
||||
self.config = {}
|
||||
self.is_running = False
|
||||
self.exception = None
|
||||
if not wsgi:
|
||||
self.setup_loggers()
|
||||
cherrypy.engine.bonjour.subscribe()
|
||||
self.config['global'] = {
|
||||
'tools.gzip.on' : True,
|
||||
'tools.gzip.mime_types': ['text/html', 'text/plain', 'text/xml', 'text/javascript', 'text/css'],
|
||||
}}
|
||||
'tools.gzip.mime_types': ['text/html', 'text/plain',
|
||||
'text/xml', 'text/javascript', 'text/css'],
|
||||
}
|
||||
if opts.password:
|
||||
self.config['/'] = {
|
||||
'tools.digest_auth.on' : True,
|
||||
'tools.digest_auth.realm' : (_('Password to access your calibre library. Username is ') + opts.username.strip()).encode('ascii', 'replace'),
|
||||
'tools.digest_auth.realm' : (
|
||||
_('Password to access your calibre library. Username is ')
|
||||
+ opts.username.strip()),
|
||||
'tools.digest_auth.users' : {opts.username.strip():opts.password.strip()},
|
||||
}
|
||||
|
||||
|
||||
self.is_running = False
|
||||
self.exception = None
|
||||
self.setup_loggers()
|
||||
cherrypy.engine.bonjour.subscribe()
|
||||
self.__dispatcher__ = DispatchController(self.opts.url_prefix, wsgi)
|
||||
for x in self.__class__.__bases__:
|
||||
if hasattr(x, 'add_routes'):
|
||||
x.add_routes(self, self.__dispatcher__)
|
||||
root_conf = self.config.get('/', {})
|
||||
root_conf['request.dispatch'] = self.__dispatcher__.dispatcher
|
||||
self.config['/'] = root_conf
|
||||
|
||||
def set_database(self, db):
|
||||
self.db = db
|
||||
@ -183,14 +198,6 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
|
||||
|
||||
def start(self):
|
||||
self.is_running = False
|
||||
d = DispatchController(self.opts.url_prefix)
|
||||
for x in self.__class__.__bases__:
|
||||
if hasattr(x, 'add_routes'):
|
||||
x.add_routes(self, d)
|
||||
root_conf = self.config.get('/', {})
|
||||
root_conf['request.dispatch'] = d.dispatcher
|
||||
self.config['/'] = root_conf
|
||||
|
||||
cherrypy.tree.mount(root=None, config=self.config)
|
||||
try:
|
||||
try:
|
||||
|
@ -460,13 +460,14 @@ class BrowseServer(object):
|
||||
@Endpoint()
|
||||
def browse_catalog(self, category=None, category_sort=None):
|
||||
'Entry point for top-level, categories and sub-categories'
|
||||
prefix = '' if self.is_wsgi else self.opts.url_prefix
|
||||
if category == None:
|
||||
ans = self.browse_toplevel()
|
||||
elif category == 'newest':
|
||||
raise cherrypy.InternalRedirect(self.opts.url_prefix +
|
||||
raise cherrypy.InternalRedirect(prefix +
|
||||
'/browse/matches/newest/dummy')
|
||||
elif category == 'allbooks':
|
||||
raise cherrypy.InternalRedirect(self.opts.url_prefix +
|
||||
raise cherrypy.InternalRedirect(prefix +
|
||||
'/browse/matches/allbooks/dummy')
|
||||
else:
|
||||
ans = self.browse_category(category, category_sort)
|
||||
|
@ -24,6 +24,17 @@ def stop_threaded_server(server):
|
||||
server.exit()
|
||||
server.thread = None
|
||||
|
||||
def create_wsgi_app(path_to_library=None, prefix=''):
|
||||
'WSGI entry point'
|
||||
from calibre.library import db
|
||||
cherrypy.config.update({'environment': 'embedded'})
|
||||
db = db(path_to_library)
|
||||
parser = option_parser()
|
||||
opts, args = parser.parse_args(['calibre-server'])
|
||||
opts.url_prefix = prefix
|
||||
server = LibraryServer(db, opts, wsgi=True, show_tracebacks=True)
|
||||
return cherrypy.Application(server, script_name=None, config=server.config)
|
||||
|
||||
def option_parser():
|
||||
parser = config().option_parser('%prog '+ _(
|
||||
'''[options]
|
||||
|
@ -121,7 +121,7 @@ def build_index(books, num, search, sort, order, start, total, url_base, CKEYS,
|
||||
A(
|
||||
fmt.lower(),
|
||||
href=prefix+'/get/%s/%s-%s_%d.%s' % (fmt, a, t,
|
||||
book['id'], fmt)
|
||||
book['id'], fmt.lower())
|
||||
),
|
||||
CLASS('button'))
|
||||
s.tail = u''
|
||||
|
104
src/calibre/manual/server.rst
Normal file
104
src/calibre/manual/server.rst
Normal file
@ -0,0 +1,104 @@
|
||||
.. include:: global.rst
|
||||
|
||||
.. _servertutorial:
|
||||
|
||||
Integrating the |app| content server into other servers
|
||||
==========================================================
|
||||
|
||||
Here, we will show you how to integrate the |app| content server into another server. The most common reason for this is to make use of SSL or more sophisticated authentication. There are two main techniques: Running the |app| content server as a standalone process and using a reverse proxy to connect it with your main server or running the content server in process in your main server with WSGI. The examples below are all for Apache 2.x on linux, but should be easily adaptable to other platforms.
|
||||
|
||||
.. contents:: Contents
|
||||
:depth: 2
|
||||
:local:
|
||||
|
||||
Using a reverse proxy
|
||||
-----------------------
|
||||
|
||||
This is the simplest approach as it allows you to use the binary calibre install with no external dependencies/system integration requirements.
|
||||
|
||||
First start the |app| content server as shown below::
|
||||
|
||||
calibre-server --url-prefix /calibre --port 8080
|
||||
|
||||
Now suppose you are using Apache as your main server. First enable the proxy modules in apache, by adding the following to :file:`httpd.conf`::
|
||||
|
||||
LoadModule proxy_module modules/mod_proxy.so
|
||||
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||
|
||||
The exact technique for enabling the proxy modules will vary depending on your Apache installation. Once you have the proxy modules enabled, add the following rules to httpd.conf (or if you are using virtual hosts to the conf file for the virtual host in question::
|
||||
|
||||
RewriteEngine on
|
||||
RewriteRule ^/calibre/(.*) http://localhost:8080/calibre/$1 [proxy]
|
||||
RewriteRule ^/calibre http://localhost:8080 [proxy]
|
||||
|
||||
That's all, you will now be able to access the |app| Content Server under the /calibre URL in your apache server.
|
||||
|
||||
.. note:: If you are willing to devote an entire VirtualHost to the content server, then there is no need to use --url-prefix and RewriteRule, instead just use the ProxyPass directive.
|
||||
|
||||
Using WSGI
|
||||
------------
|
||||
|
||||
The calibre content server can be run directly, in process, inside a host server like Apache using the WSGI framework.
|
||||
|
||||
First, we have to create a WSGI *adapter* for the calibre content server. Here is a template you can use for the purpose. Replace the paths as directed in the comments
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# WSGI script file to run calibre content server as a WSGI app
|
||||
|
||||
import sys, os
|
||||
|
||||
|
||||
# You can get the paths referenced here by running
|
||||
# calibre-debug --paths
|
||||
# on your server
|
||||
|
||||
# The first entry from CALIBRE_PYTHON_PATH
|
||||
sys.path.insert(0, '/home/kovid/work/calibre/src')
|
||||
|
||||
# CALIBRE_RESOURCES_PATH
|
||||
sys.resources_location = '/home/kovid/work/calibre/resources'
|
||||
|
||||
# CALIBRE_EXTENSIONS_PATH
|
||||
sys.extensions_location = '/home/kovid/work/calibre/src/calibre/plugins'
|
||||
|
||||
# Path to directory containing calibre executables
|
||||
sys.executables_location = '/usr/bin'
|
||||
|
||||
# Path to a directory for which the server has read/write permissions
|
||||
# calibre config will be stored here
|
||||
os.environ['CALIBRE_CONFIG_DIRECTORY'] = '/var/www/localhost/calibre-config'
|
||||
|
||||
del sys
|
||||
del os
|
||||
|
||||
from calibre.library.server.main import create_wsgi_app
|
||||
application = create_wsgi_app(
|
||||
# The mount point of this WSGI application (i.e. the first argument to
|
||||
# the WSGIScriptAlias directive). Set to empty string is mounted at /
|
||||
prefix='/calibre',
|
||||
|
||||
# Path to the calibre library to be served
|
||||
# The server process must have write permission for all files/dirs
|
||||
# in this directory or BAD things will happen
|
||||
path_to_library='/home/kovid/documents/demo library'
|
||||
)
|
||||
|
||||
del create_wsgi_app
|
||||
|
||||
Save this adapter as :file:`calibre-wsgi-adpater.py` somewhere your server will have access to it.
|
||||
|
||||
Let's suppose that we want to use WSGI in Apache. First enable WSGI in Apache by adding the following to :file:`httpd.conf`::
|
||||
|
||||
LoadModule proxy_module modules/mod_wsgi.so
|
||||
|
||||
The exact technique for enabling the wsgi module will vary depending on your Apache installation. Once you have the proxy modules enabled, add the following rules to httpd.conf (or if you are using virtual hosts to the conf file for the virtual host in question::
|
||||
|
||||
WSGIScriptAlias /calibre /var/www/localhost/cgi-bin/calibre-wsgi-adapter.py
|
||||
|
||||
Change the path to :file:`calibre-wsgi-adapter.py` to wherever you saved it previously (make sure Apache has access to it).
|
||||
|
||||
That's all, you will now be able to access the |app| Content Server under the /calibre URL in your apache server.
|
||||
|
||||
.. note:: For more help with using mod_wsgi in Apache, see `mod_wsgi <http://code.google.com/p/modwsgi/wiki/WhereToGetHelp>`_.
|
||||
|
@ -16,4 +16,5 @@ Here you will find tutorials to get you started using |app|'s more advanced feat
|
||||
template_lang
|
||||
regexp
|
||||
portable
|
||||
server
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user