diff --git a/dddp/server/.views.py.swp b/dddp/server/.views.py.swp
new file mode 100644
index 0000000..934a421
Binary files /dev/null and b/dddp/server/.views.py.swp differ
diff --git a/dddp/server/__init__.py b/dddp/server/__init__.py
new file mode 100644
index 0000000..cea26b4
--- /dev/null
+++ b/dddp/server/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'dddp.server.apps.ServerConfig'
diff --git a/dddp/server/apps.py b/dddp/server/apps.py
new file mode 100644
index 0000000..6a1b915
--- /dev/null
+++ b/dddp/server/apps.py
@@ -0,0 +1,190 @@
+"""Django DDP Server app config."""
+from __future__ import print_function, absolute_import, unicode_literals
+
+import io
+import os.path
+
+from django.apps import AppConfig
+from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
+from ejson import dumps, loads
+import pybars
+
+
+STAR_JSON_SETTING_NAME = 'METEOR_STAR_JSON'
+
+
+def read(path, default=None, encoding='utf8'):
+ """Read encoded contents from specified path or return default."""
+ if not path:
+ return default
+ try:
+ with io.open(path, mode='r', encoding=encoding) as contents:
+ return contents.read()
+ except IOError:
+ if default is not None:
+ return default
+ raise
+
+
+def read_json(path):
+ """Read JSON encoded contents from specified path."""
+ with open(path, mode='r') as json_file:
+ return loads(json_file.read())
+
+
+class ServerConfig(AppConfig):
+
+ """Django config for dddp.server app."""
+
+ name = 'dddp.server'
+ verbose_name = 'Django DDP Meteor Web Server'
+
+ manifest = None
+ program_json = None
+ program_json_path = None
+ runtime_config = None
+
+ star_json = None # top level layout
+ server_json = None # web server layout
+ web_browser_json = None # web.browser (client) layout
+
+ url_map = None
+ internal_map = None
+ server_load_map = None
+ template_path = None # web server HTML template path
+ client_map = None # web.browser (client) URL to path map
+ html = '\n
DDP App'
+
+ def ready(self):
+ """Configure Django DDP server app."""
+ self.url_map = {}
+
+ try:
+ json_path = getattr(settings, STAR_JSON_SETTING_NAME)
+ except AttributeError:
+ raise ImproperlyConfigured(
+ '%s setting required by dddp.server.view.' % (
+ STAR_JSON_SETTING_NAME,
+ ),
+ )
+
+ self.star_json = read_json(json_path)
+ star_format = self.star_json['format']
+ if star_format != 'site-archive-pre1':
+ raise ValueError(
+ 'Unknown Meteor star format: %r' % star_format,
+ )
+ programs = {
+ program['name']: program
+ for program in self.star_json['programs']
+ }
+
+ server_json_path = os.path.join(
+ os.path.dirname(json_path),
+ os.path.dirname(programs['server']['path']),
+ 'program.json',
+ )
+ self.server_json = read_json(server_json_path)
+ server_format = self.server_json['format']
+ if server_format != 'javascript-image-pre1':
+ raise ValueError(
+ 'Unknown Meteor server format: %r' % server_format,
+ )
+ self.server_load_map = {}
+ for item in self.server_json['load']:
+ item['path_full'] = os.path.join(
+ os.path.dirname(server_json_path),
+ item['path'],
+ )
+ self.server_load_map[item['path']] = item
+ self.url_map[item['path']] = (
+ item['path_full'], 'text/javascript'
+ )
+ try:
+ item['source_map_full'] = os.path.join(
+ os.path.dirname(server_json_path),
+ item['sourceMap'],
+ )
+ self.url_map[item['sourceMap']] = (
+ item['source_map_full'], 'text/plain'
+ )
+ except KeyError:
+ pass
+ self.template_path = os.path.join(
+ os.path.dirname(server_json_path),
+ self.server_load_map[
+ 'packages/boilerplate-generator.js'
+ ][
+ 'assets'
+ ][
+ 'boilerplate_web.browser.html'
+ ],
+ )
+
+ web_browser_json_path = os.path.join(
+ os.path.dirname(json_path),
+ programs['web.browser']['path'],
+ )
+ self.web_browser_json = read_json(web_browser_json_path)
+ web_browser_format = self.web_browser_json['format']
+ if web_browser_format != 'web-program-pre1':
+ raise ValueError(
+ 'Unknown Meteor web.browser format: %r' % (
+ web_browser_format,
+ ),
+ )
+ self.client_map = {}
+ self.internal_map = {}
+ for item in self.web_browser_json['manifest']:
+ item['path_full'] = os.path.join(
+ os.path.dirname(web_browser_json_path),
+ item['path'],
+ )
+ if item['where'] == 'client':
+ if '?' in item['url']:
+ item['url'] = item['url'].split('?', 1)[0]
+ self.client_map[item['url']] = item
+ self.url_map[item['url']] = (
+ item['path_full'],
+ {
+ 'js': 'text/javascript',
+ 'css': 'text/css',
+ }.get(
+ item['type'], 'application/octet-stream',
+ ),
+ )
+ elif item['where'] == 'internal':
+ self.internal_map[item['type']] = item
+
+ config = {
+ 'css': [
+ {'url': item['path']}
+ for item in self.web_browser_json['manifest']
+ if item['type'] == 'css' and item['where'] == 'client'
+ ],
+ 'js': [
+ {'url': item['path']}
+ for item in self.web_browser_json['manifest']
+ if item['type'] == 'js' and item['where'] == 'client'
+ ],
+ 'meteorRuntimeConfig': '"%s"' % (
+ dumps(self.runtime_config)
+ ),
+ 'rootUrlPathPrefix': '/app',
+ 'bundledJsCssPrefix': '/app/',
+ 'inlineScriptsAllowed': False,
+ 'inline': None,
+ 'head': read(
+ self.internal_map.get('head', {}).get('path_full', None),
+ default=u'',
+ ),
+ 'body': read(
+ self.internal_map.get('body', {}).get('path_full', None),
+ default=u'',
+ ),
+ }
+ tmpl_raw = read(self.template_path, encoding='utf8')
+ compiler = pybars.Compiler()
+ tmpl = compiler.compile(tmpl_raw)
+ self.html = '\n%s' % tmpl(config)
diff --git a/dddp/server/views.py b/dddp/server/views.py
new file mode 100644
index 0000000..c30fd30
--- /dev/null
+++ b/dddp/server/views.py
@@ -0,0 +1,49 @@
+"""Django DDP Server views."""
+from __future__ import print_function, absolute_import
+from ejson import dumps
+from django.apps import apps
+from django.http import HttpResponse
+from django.views.generic import View
+
+
+STAR_JSON_SETTING_NAME = 'METEOR_STAR_JSON'
+
+
+class MeteorView(View):
+
+ """Django DDP Meteor server view."""
+
+ http_method_names = ['get', 'head']
+
+ app = None
+ runtime_config = None
+
+ def __init__(self, **kwargs):
+ """Initialisation for Django DDP server view."""
+ super(MeteorView, self).__init__(**kwargs)
+ self.app = apps.get_app_config('server')
+
+ def get(self, request, path):
+ """Return HTML (or other related content) for Meteor."""
+ if path == '/meteor_runtime_config.js':
+ config = {
+ 'DDP_DEFAULT_CONNECTION_URL': request.build_absolute_uri('/'),
+ 'ROOT_URL': request.build_absolute_uri('/'),
+ 'ROOT_URL_PATH_PREFIX': '',
+ }
+ config.update(self.runtime_config)
+ return HttpResponse(
+ '__meteor_runtime_config__ = %s;' % dumps(config),
+ content_type='text/javascript',
+ )
+ try:
+ file_path, content_type = self.app.url_map[path]
+ with open(file_path, 'r') as content:
+ return HttpResponse(
+ content.read(),
+ content_type=content_type,
+ )
+ except KeyError:
+ print(path)
+ return HttpResponse(self.app.html)
+ #raise Http404