1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import logging 6 7 from data_source import DataSource 8 from docs_server_utils import StringIdentity 9 from environment import IsPreviewServer 10 from file_system import FileNotFoundError 11 from future import Future, All 12 from jsc_view import JSCView, GetEventByNameFromEvents 13 from platform_util import GetPlatforms 14 from samples_data_source import CreateSamplesView 15 16 17 class APIDataSource(DataSource): 18 '''This class fetches and loads JSON APIs from the FileSystem passed in with 19 |compiled_fs_factory|, so the APIs can be plugged into templates. 20 ''' 21 def __init__(self, server_instance, request): 22 file_system = server_instance.host_file_system_provider.GetMaster() 23 self._json_cache = server_instance.compiled_fs_factory.ForJson(file_system) 24 self._template_cache = server_instance.compiled_fs_factory.ForTemplates( 25 file_system) 26 self._platform_bundle = server_instance.platform_bundle 27 self._view_cache = server_instance.object_store_creator.Create( 28 APIDataSource, 29 # Update the models when any of templates, APIs, or Features change. 30 category=StringIdentity(self._json_cache.GetIdentity(), 31 self._template_cache.GetIdentity(), 32 self._platform_bundle.GetIdentity())) 33 34 # This caches the result of _LoadEventByName. 35 self._event_byname_futures = {} 36 self._request = request 37 38 def _LoadEventByName(self, platform): 39 '''All events have some members in common. We source their description 40 from Event in events.json. 41 ''' 42 if platform not in self._event_byname_futures: 43 future = self._GetSchemaView(platform, 'events') 44 self._event_byname_futures[platform] = Future( 45 callback=lambda: GetEventByNameFromEvents(future.Get())) 46 return self._event_byname_futures[platform] 47 48 def _GetSchemaView(self, platform, api_name): 49 object_store_key = '/'.join((platform, api_name)) 50 api_models = self._platform_bundle.GetAPIModels(platform) 51 jsc_view_future = self._view_cache.Get(object_store_key) 52 model_future = api_models.GetModel(api_name) 53 content_script_apis_future = api_models.GetContentScriptAPIs() 54 def resolve(): 55 jsc_view = jsc_view_future.Get() 56 if jsc_view is None: 57 jsc_view = JSCView( 58 content_script_apis_future.Get(), 59 model_future.Get(), 60 self._platform_bundle.GetAvailabilityFinder(platform), 61 self._json_cache, 62 self._template_cache, 63 self._platform_bundle.GetFeaturesBundle(platform), 64 self._LoadEventByName(platform), 65 platform).ToDict() 66 self._view_cache.Set(object_store_key, jsc_view) 67 return jsc_view 68 return Future(callback=resolve) 69 70 def _GetImpl(self, platform, api_name): 71 jsc_view_future = self._GetSchemaView(platform, api_name) 72 def resolve(): 73 jsc_view = jsc_view_future.Get() 74 # Parsing samples on the preview server takes seconds and doesn't add 75 # anything. Don't do it. 76 if not IsPreviewServer(): 77 samples_model = self._platform_bundle.GetSamplesModel(platform) 78 # Creates an object that lazily gets samples. 79 jsc_view['samples'] = type('getter', (object,), { 80 'get': lambda _, platform: CreateSamplesView( 81 samples_model.FilterSamples(jsc_view['name']), self._request) 82 })() 83 return jsc_view 84 return Future(callback=resolve) 85 86 def get(self, platform): 87 '''Return a getter object so that templates can perform lookups such 88 as apis.extensions.runtime. 89 ''' 90 getter = lambda: 0 91 getter.get = lambda api_name: self._GetImpl(platform, api_name).Get() 92 return getter 93 94 def GetRefreshPaths(self): 95 tasks = [] 96 for platform in GetPlatforms(): 97 tasks += ['%s/%s' % (platform, api) 98 for api in 99 self._platform_bundle.GetAPIModels(platform).GetNames()] 100 return tasks 101 102 def Refresh(self, path): 103 platform, api = path.split('/') 104 logging.info('Refreshing %s/%s' % (platform, api)) 105 future = self._GetImpl(platform, api) 106 return All([future], except_pass=FileNotFoundError) 107