| Index: pkg/appengine/lib/src/server/context_registry.dart
|
| diff --git a/pkg/appengine/lib/src/server/context_registry.dart b/pkg/appengine/lib/src/server/context_registry.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e850185cd40fc2bb4ebae39e4252d8178ab78f7a
|
| --- /dev/null
|
| +++ b/pkg/appengine/lib/src/server/context_registry.dart
|
| @@ -0,0 +1,139 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library appengine.context_registry;
|
| +
|
| +import 'dart:async';
|
| +
|
| +import 'package:memcache/memcache.dart' as memcache;
|
| +import 'package:memcache/src/memcache_impl.dart' as memcache_impl;
|
| +import 'package:gcloud/db.dart' as db;
|
| +import 'package:gcloud/storage.dart' as storage;
|
| +
|
| +import 'http_wrapper.dart';
|
| +import 'assets.dart';
|
| +
|
| +import '../../appengine.dart';
|
| +import '../appengine_context.dart';
|
| +import '../protobuf_api/rpc/rpc_service.dart';
|
| +import '../api_impl/logging_impl.dart' as logging_impl;
|
| +import '../api_impl/modules_impl.dart' as modules_impl;
|
| +import '../api_impl/raw_memcache_impl.dart' as raw_memcache_impl;
|
| +import '../api_impl/remote_api_impl.dart' as remote_api_impl;
|
| +import '../api_impl/raw_datastore_v3_impl.dart' as raw_datastore_v3_impl;
|
| +import '../api_impl/users_impl.dart' as users_impl;
|
| +
|
| +class ContextRegistry {
|
| + static const HTTP_HEADER_APPENGINE_TICKET = 'x-appengine-api-ticket';
|
| + static const HTTP_HEADER_DEVAPPSERVER_REQUEST_ID =
|
| + 'x-appengine-dev-request-id';
|
| +
|
| + final RPCService _rpcService;
|
| + final storage.Storage _storage;
|
| + final AppengineContext _appengineContext;
|
| + final Map<AppengineHttpRequest, ClientContext> _request2context = {};
|
| + db.ModelDB _modelDB;
|
| +
|
| + ContextRegistry(this._rpcService, this._storage, this._appengineContext) {
|
| + // TODO: We should provide an API to allow users providing us with either a
|
| + // different [ModelDB] object or specify a list of libraries to scan for
|
| + // models.
|
| + _modelDB = new db.ModelDBImpl();
|
| + }
|
| +
|
| + ClientContext add(AppengineHttpRequest request) {
|
| + var ticket = request.headers.value(HTTP_HEADER_APPENGINE_TICKET);
|
| + if (ticket == null) {
|
| + ticket = request.headers.value(HTTP_HEADER_DEVAPPSERVER_REQUEST_ID);
|
| + if (ticket == null) {
|
| + ticket = 'invalid-ticket';
|
| + }
|
| + }
|
| + var services = _getServices(ticket, request);
|
| + var assets = new AssetsImpl(request, _appengineContext);
|
| + var context =
|
| + new _ClientContextImpl(
|
| + services, assets, _appengineContext.isDevelopmentEnvironment);
|
| + _request2context[request] = context;
|
| +
|
| + request.response.registerHook(
|
| + () => services.logging.flush().catchError((_) {}));
|
| +
|
| + return context;
|
| + }
|
| +
|
| + ClientContext lookup(AppengineHttpRequest request) {
|
| + return _request2context[request];
|
| + }
|
| +
|
| + Future remove(AppengineHttpRequest request) {
|
| + _request2context.remove(request);
|
| + return new Future.value();
|
| + }
|
| +
|
| + Services newBackgroundServices()
|
| + => _getServices(_appengineContext.backgroundTicket, null);
|
| +
|
| + Services _getServices(String ticket, AppengineHttpRequest request) {
|
| + var raw_memcache =
|
| + new raw_memcache_impl.RawMemcacheRpcImpl(_rpcService, ticket);
|
| + var serviceMap = {
|
| + // Create a new logging instance for every request, but use the background
|
| + // ticket, so we can flush logs at the end of the request.
|
| + 'logging': new logging_impl.LoggingRpcImpl(_rpcService, ticket),
|
| + 'raw_memcache': raw_memcache,
|
| + 'raw_datastore_v3' : new raw_datastore_v3_impl.DatastoreV3RpcImpl(
|
| + _rpcService, _appengineContext, ticket),
|
| + 'remote_api' : new remote_api_impl.RemoteApiImpl(
|
| + _rpcService, _appengineContext, ticket),
|
| + 'modules' : new modules_impl.ModulesRpcImpl(
|
| + _rpcService, _appengineContext, ticket),
|
| + };
|
| + if (request != null) {
|
| + serviceMap['users'] =
|
| + new users_impl.UserRpcImpl(_rpcService, ticket, request);
|
| + }
|
| + serviceMap['memcache'] =
|
| + new memcache_impl.MemCacheImpl(serviceMap['raw_memcache']);
|
| + serviceMap['db'] =
|
| + new db.DatastoreDB(serviceMap['raw_datastore_v3'], modelDB: _modelDB);
|
| + serviceMap['storage'] = _storage;
|
| + return new _ServicesImpl(serviceMap);
|
| + }
|
| +}
|
| +
|
| +class _ClientContextImpl implements ClientContext {
|
| + final Services services;
|
| + final Assets assets;
|
| + final bool _isDevelopmentEnvironment;
|
| +
|
| + _ClientContextImpl(
|
| + this.services, this.assets, this._isDevelopmentEnvironment);
|
| +
|
| + bool get isDevelopmentEnvironment => _isDevelopmentEnvironment;
|
| + bool get isProductionEnvironment => !_isDevelopmentEnvironment;
|
| +}
|
| +
|
| +class _ServicesImpl extends Services {
|
| + // TODO:
|
| + // - consider removing the map
|
| + // - consider building the services on demand
|
| + final Map<String, dynamic> _serviceMap;
|
| +
|
| + _ServicesImpl(this._serviceMap);
|
| +
|
| + db.DatastoreDB get db => _serviceMap['db'];
|
| +
|
| + storage.Storage get storage => _serviceMap['storage'];
|
| +
|
| + Logging get logging => _serviceMap['logging'];
|
| +
|
| + memcache.Memcache get memcache => _serviceMap['memcache'];
|
| +
|
| + ModulesService get modules => _serviceMap['modules'];
|
| +
|
| + RemoteApi get remoteApi => _serviceMap['remote_api'];
|
| +
|
| + UserService get users => _serviceMap['users'];
|
| +}
|
|
|