##// END OF EJS Templates
don't require tornado 3 in `--post serve`...
MinRK -
Show More
@@ -1,107 +1,111 b''
1 """PostProcessor for serving reveal.js HTML slideshows."""
1 """PostProcessor for serving reveal.js HTML slideshows."""
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 #Copyright (c) 2013, the IPython Development Team.
3 #Copyright (c) 2013, the IPython Development Team.
4 #
4 #
5 #Distributed under the terms of the Modified BSD License.
5 #Distributed under the terms of the Modified BSD License.
6 #
6 #
7 #The full license is in the file COPYING.txt, distributed with this software.
7 #The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 import os
14 import os
15 import webbrowser
15 import webbrowser
16
16
17 from tornado import web, ioloop, httpserver
17 from tornado import web, ioloop, httpserver
18 from tornado.httpclient import AsyncHTTPClient
18 from tornado.httpclient import AsyncHTTPClient
19
19
20 from IPython.utils.traitlets import Bool, Unicode, Int
20 from IPython.utils.traitlets import Bool, Unicode, Int
21
21
22 from .base import PostProcessorBase
22 from .base import PostProcessorBase
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Classes
25 # Classes
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 class ProxyHandler(web.RequestHandler):
28 class ProxyHandler(web.RequestHandler):
29 """handler the proxies requests from a local prefix to a CDN"""
29 """handler the proxies requests from a local prefix to a CDN"""
30 @web.asynchronous
30 @web.asynchronous
31 def get(self, prefix, url):
31 def get(self, prefix, url):
32 """proxy a request to a CDN"""
32 """proxy a request to a CDN"""
33 proxy_url = "/".join([self.settings['cdn'], url])
33 proxy_url = "/".join([self.settings['cdn'], url])
34 client = self.settings['client']
34 client = self.settings['client']
35 client.fetch(proxy_url, callback=self.finish_get)
35 client.fetch(proxy_url, callback=self.finish_get)
36
36
37 def finish_get(self, response):
37 def finish_get(self, response):
38 """finish the request"""
38 """finish the request"""
39 # copy potentially relevant headers
39 # copy potentially relevant headers
40 for header in ["Content-Type", "Cache-Control", "Date", "Last-Modified", "Expires"]:
40 for header in ["Content-Type", "Cache-Control", "Date", "Last-Modified", "Expires"]:
41 if header in response.headers:
41 if header in response.headers:
42 self.set_header(header, response.headers[header])
42 self.set_header(header, response.headers[header])
43 self.finish(response.body)
43 self.finish(response.body)
44
44
45 class ServePostProcessor(PostProcessorBase):
45 class ServePostProcessor(PostProcessorBase):
46 """Post processor designed to serve files
46 """Post processor designed to serve files
47
47
48 Proxies reveal.js requests to a CDN if no local reveal.js is present
48 Proxies reveal.js requests to a CDN if no local reveal.js is present
49 """
49 """
50
50
51
51
52 open_in_browser = Bool(True, config=True,
52 open_in_browser = Bool(True, config=True,
53 help="""Should the browser be opened automatically?"""
53 help="""Should the browser be opened automatically?"""
54 )
54 )
55 reveal_cdn = Unicode("https://cdn.jsdelivr.net/reveal.js/2.4.0", config=True,
55 reveal_cdn = Unicode("https://cdn.jsdelivr.net/reveal.js/2.4.0", config=True,
56 help="""URL for reveal.js CDN."""
56 help="""URL for reveal.js CDN."""
57 )
57 )
58 reveal_prefix = Unicode("reveal.js", config=True, help="URL prefix for reveal.js")
58 reveal_prefix = Unicode("reveal.js", config=True, help="URL prefix for reveal.js")
59 ip = Unicode("127.0.0.1", config=True, help="The IP address to listen on.")
59 ip = Unicode("127.0.0.1", config=True, help="The IP address to listen on.")
60 port = Int(8000, config=True, help="port for the server to listen on.")
60 port = Int(8000, config=True, help="port for the server to listen on.")
61
61
62 def postprocess(self, input):
62 def postprocess(self, input):
63 """Serve the build directory with a webserver."""
63 """Serve the build directory with a webserver."""
64 dirname, filename = os.path.split(input)
64 dirname, filename = os.path.split(input)
65 handlers = [
65 handlers = [
66 (r"/(.+)", web.StaticFileHandler, {'path' : dirname}),
66 (r"/(.+)", web.StaticFileHandler, {'path' : dirname}),
67 (r"/", web.RedirectHandler, {"url": "/%s" % filename})
67 (r"/", web.RedirectHandler, {"url": "/%s" % filename})
68 ]
68 ]
69
69
70 if ('://' in self.reveal_prefix or self.reveal_prefix.startswith("//")):
70 if ('://' in self.reveal_prefix or self.reveal_prefix.startswith("//")):
71 # reveal specifically from CDN, nothing to do
71 # reveal specifically from CDN, nothing to do
72 pass
72 pass
73 elif os.path.isdir(os.path.join(dirname, self.reveal_prefix)):
73 elif os.path.isdir(os.path.join(dirname, self.reveal_prefix)):
74 # reveal prefix exists
74 # reveal prefix exists
75 self.log.info("Serving local %s", self.reveal_prefix)
75 self.log.info("Serving local %s", self.reveal_prefix)
76 else:
76 else:
77 self.log.info("Redirecting %s requests to %s", self.reveal_prefix, self.reveal_cdn)
77 self.log.info("Redirecting %s requests to %s", self.reveal_prefix, self.reveal_cdn)
78 handlers.insert(0, (r"/(%s)/(.*)" % self.reveal_prefix, ProxyHandler))
78 handlers.insert(0, (r"/(%s)/(.*)" % self.reveal_prefix, ProxyHandler))
79
79
80 app = web.Application(handlers,
80 app = web.Application(handlers,
81 cdn=self.reveal_cdn,
81 cdn=self.reveal_cdn,
82 client=AsyncHTTPClient(),
82 client=AsyncHTTPClient(),
83 )
83 )
84 # hook up tornado logging to our logger
84 # hook up tornado logging to our logger
85 from tornado import log
85 try:
86 log.app_log = self.log
86 from tornado import log
87 log.app_log = self.log
88 except ImportError:
89 # old tornado (<= 3), ignore
90 pass
87
91
88 http_server = httpserver.HTTPServer(app)
92 http_server = httpserver.HTTPServer(app)
89 http_server.listen(self.port, address=self.ip)
93 http_server.listen(self.port, address=self.ip)
90 url = "http://%s:%i/%s" % (self.ip, self.port, filename)
94 url = "http://%s:%i/%s" % (self.ip, self.port, filename)
91 print("Serving your slides at %s" % url)
95 print("Serving your slides at %s" % url)
92 print("Use Control-C to stop this server")
96 print("Use Control-C to stop this server")
93 if self.open_in_browser:
97 if self.open_in_browser:
94 webbrowser.open(url, new=2)
98 webbrowser.open(url, new=2)
95 try:
99 try:
96 ioloop.IOLoop.instance().start()
100 ioloop.IOLoop.instance().start()
97 except KeyboardInterrupt:
101 except KeyboardInterrupt:
98 print("\nInterrupted")
102 print("\nInterrupted")
99
103
100 def main(path):
104 def main(path):
101 """allow running this module to serve the slides"""
105 """allow running this module to serve the slides"""
102 server = ServePostProcessor()
106 server = ServePostProcessor()
103 server(path)
107 server(path)
104
108
105 if __name__ == '__main__':
109 if __name__ == '__main__':
106 import sys
110 import sys
107 main(sys.argv[1])
111 main(sys.argv[1])
General Comments 0
You need to be logged in to leave comments. Login now