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