blob: c96be0f3710b0eff1998d1f8502b3f930eff53a6 [file] [log] [blame]
Zsolt Haraszti3d55ffc2016-10-03 22:26:41 -07001#!/usr/bin/env python
2#
3# Copyright 2016 the original author or authors.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import os
19
20from klein import Klein
21from simplejson import dumps, load
22from structlog import get_logger
23from twisted.internet import reactor, endpoints
24from twisted.internet.defer import inlineCallbacks, returnValue
25from twisted.internet.tcp import Port
26from twisted.web.server import Site
27from twisted.web.static import File
Zsolt Harasztie7b60762016-10-05 17:49:27 -070028from werkzeug.exceptions import BadRequest
Zsolt Haraszti3d55ffc2016-10-03 22:26:41 -070029
30log = get_logger()
31
Zsolt Haraszti3d55ffc2016-10-03 22:26:41 -070032
33class WebServer(object):
34
35 app = Klein()
36
37 def __init__(self, port, work_dir, grpc_client):
38 self.port = port
39 self.site = None
40 self.work_dir = work_dir
41 self.grpc_client = grpc_client
42
43 self.swagger_ui_root_dir = os.path.abspath(
44 os.path.join(os.path.dirname(__file__), '../swagger_ui'))
45
46 self.tcp_port = None
Zsolt Harasztie7b60762016-10-05 17:49:27 -070047 self.shutting_down = False
Zsolt Haraszti3d55ffc2016-10-03 22:26:41 -070048
49 @inlineCallbacks
Zsolt Harasztidca6fa12016-11-03 16:56:17 -070050 def start(self):
51 log.debug('starting')
Zsolt Haraszti3d55ffc2016-10-03 22:26:41 -070052 yield self._open_endpoint()
Zsolt Harasztidca6fa12016-11-03 16:56:17 -070053 log.info('started')
Zsolt Haraszti3d55ffc2016-10-03 22:26:41 -070054 returnValue(self)
55
Zsolt Haraszti3d55ffc2016-10-03 22:26:41 -070056 @inlineCallbacks
Zsolt Harasztidca6fa12016-11-03 16:56:17 -070057 def stop(self):
58 log.debug('stopping')
59 self.shutting_down = True
60 if self.tcp_port is not None:
61 assert isinstance(self.tcp_port, Port)
62 yield self.tcp_port.socket.close()
63 log.info('stopped')
64
65 @inlineCallbacks
Zsolt Haraszti3d55ffc2016-10-03 22:26:41 -070066 def _open_endpoint(self):
67 endpoint = endpoints.TCP4ServerEndpoint(reactor, self.port)
68 self.site = Site(self.app.resource())
69 self.tcp_port = yield endpoint.listen(self.site)
70 log.info('web-server-started', port=self.port)
71 self.endpoint = endpoint
72
Zsolt Harasztie7b60762016-10-05 17:49:27 -070073 def reload_generated_routes(self):
74 for fname in os.listdir(self.work_dir):
75 if fname.endswith('_gw.py'):
76 module_name = fname.replace('.py', '')
77 m = __import__(module_name)
78 assert hasattr(m, 'add_routes')
79 m.add_routes(self.app, self.grpc_client)
80 log.info('routes-loaded', module=module_name)
81
Zsolt Haraszti3d55ffc2016-10-03 22:26:41 -070082 # static swagger_ui website as landing page (for now)
83
84 @app.route('/', branch=True)
85 def static(self, request):
86 try:
87 log.debug(request=request)
88 return File(self.swagger_ui_root_dir)
89 except Exception, e:
90 log.exception('file-not-found', request=request)
91
92 # static swagger.json file to serve the schema
93
94 @app.route('/v1/swagger.json')
95 def swagger_json(self, request):
96 try:
97 return File(os.path.join(self.work_dir, 'swagger.json'))
98 except Exception, e:
99 log.exception('file-not-found', request=request)