| 'use strict'; | 
|   | 
| const delegate = require('delegates'); | 
| const { assign } = require('utility'); | 
| const eggUtils = require('egg-core').utils; | 
|   | 
| const HELPER = Symbol('Context#helper'); | 
| const LOCALS = Symbol('Context#locals'); | 
| const LOCALS_LIST = Symbol('Context#localsList'); | 
| const COOKIES = Symbol('Context#cookies'); | 
| const CONTEXT_LOGGERS = Symbol('Context#logger'); | 
| const CONTEXT_HTTPCLIENT = Symbol('Context#httpclient'); | 
| const CONTEXT_ROUTER = Symbol('Context#router'); | 
|   | 
| const proto = module.exports = { | 
|   | 
|   /** | 
|    * Get the current visitor's cookies. | 
|    */ | 
|   get cookies() { | 
|     if (!this[COOKIES]) { | 
|       this[COOKIES] = new this.app.ContextCookies(this, this.app.keys); | 
|     } | 
|     return this[COOKIES]; | 
|   }, | 
|   | 
|   /** | 
|    * Get a wrapper httpclient instance contain ctx in the hold request process | 
|    * | 
|    * @return {ContextHttpClient} the wrapper httpclient instance | 
|    */ | 
|   get httpclient() { | 
|     if (!this[CONTEXT_HTTPCLIENT]) { | 
|       this[CONTEXT_HTTPCLIENT] = new this.app.ContextHttpClient(this); | 
|     } | 
|     return this[CONTEXT_HTTPCLIENT]; | 
|   }, | 
|   | 
|   /** | 
|    * Shortcut for httpclient.curl | 
|    * | 
|    * @function Context#curl | 
|    * @param {String|Object} url - request url address. | 
|    * @param {Object} [options] - options for request. | 
|    * @return {Object} see {@link ContextHttpClient#curl} | 
|    */ | 
|   curl(url, options) { | 
|     return this.httpclient.curl(url, options); | 
|   }, | 
|   | 
|   /** | 
|    * Alias to {@link Application#router} | 
|    * | 
|    * @member {Router} Context#router | 
|    * @since 1.0.0 | 
|    * @example | 
|    * ```js | 
|    * this.router.pathFor('post', { id: 12 }); | 
|    * ``` | 
|    */ | 
|   get router() { | 
|     if (!this[CONTEXT_ROUTER]) { | 
|       this[CONTEXT_ROUTER] = this.app.router; | 
|     } | 
|     return this[CONTEXT_ROUTER]; | 
|   }, | 
|   | 
|   /** | 
|    * Set router to Context, only use on EggRouter | 
|    * @param {EggRouter} val router instance | 
|    */ | 
|   set router(val) { | 
|     this[CONTEXT_ROUTER] = val; | 
|   }, | 
|   | 
|   /** | 
|    * Get helper instance from {@link Application#Helper} | 
|    * | 
|    * @member {Helper} Context#helper | 
|    * @since 1.0.0 | 
|    */ | 
|   get helper() { | 
|     if (!this[HELPER]) { | 
|       this[HELPER] = new this.app.Helper(this); | 
|     } | 
|     return this[HELPER]; | 
|   }, | 
|   | 
|   /** | 
|    * Wrap app.loggers with context infomation, | 
|    * if a custom logger is defined by naming aLogger, then you can `ctx.getLogger('aLogger')` | 
|    * | 
|    * @param {String} name - logger name | 
|    * @return {Logger} logger | 
|    */ | 
|   getLogger(name) { | 
|     let cache = this[CONTEXT_LOGGERS]; | 
|     if (!cache) { | 
|       cache = this[CONTEXT_LOGGERS] = {}; | 
|     } | 
|   | 
|     // read from cache | 
|     if (cache[name]) return cache[name]; | 
|   | 
|     // get no exist logger | 
|     const appLogger = this.app.getLogger(name); | 
|     if (!appLogger) return null; | 
|   | 
|     // write to cache | 
|     cache[name] = new this.app.ContextLogger(this, appLogger); | 
|     return cache[name]; | 
|   }, | 
|   | 
|   /** | 
|    * Logger for Application, wrapping app.coreLogger with context infomation | 
|    * | 
|    * @member {ContextLogger} Context#logger | 
|    * @since 1.0.0 | 
|    * @example | 
|    * ```js | 
|    * this.logger.info('some request data: %j', this.request.body); | 
|    * this.logger.warn('WARNING!!!!'); | 
|    * ``` | 
|    */ | 
|   get logger() { | 
|     return this.getLogger('logger'); | 
|   }, | 
|   | 
|   /** | 
|    * Logger for frameworks and plugins, | 
|    * wrapping app.coreLogger with context infomation | 
|    * | 
|    * @member {ContextLogger} Context#coreLogger | 
|    * @since 1.0.0 | 
|    */ | 
|   get coreLogger() { | 
|     return this.getLogger('coreLogger'); | 
|   }, | 
|   | 
|   /** | 
|    * locals is an object for view, you can use `app.locals` and `ctx.locals` to set variables, | 
|    * which will be used as data when view is rendering. | 
|    * The difference between `app.locals` and `ctx.locals` is the context level, `app.locals` is global level, and `ctx.locals` is request level. when you get `ctx.locals`, it will merge `app.locals`. | 
|    * | 
|    * when you set locals, only object is available | 
|    * | 
|    * ```js | 
|    * this.locals = { | 
|    *   a: 1 | 
|    * }; | 
|    * this.locals = { | 
|    *   b: 1 | 
|    * }; | 
|    * this.locals.c = 1; | 
|    * console.log(this.locals); | 
|    * { | 
|    *   a: 1, | 
|    *   b: 1, | 
|    *   c: 1, | 
|    * }; | 
|    * ``` | 
|    * | 
|    * `ctx.locals` has cache, it only merges `app.locals` once in one request. | 
|    * | 
|    * @member {Object} Context#locals | 
|    */ | 
|   get locals() { | 
|     if (!this[LOCALS]) { | 
|       this[LOCALS] = assign({}, this.app.locals); | 
|     } | 
|     if (this[LOCALS_LIST] && this[LOCALS_LIST].length) { | 
|       assign(this[LOCALS], this[LOCALS_LIST]); | 
|       this[LOCALS_LIST] = null; | 
|     } | 
|     return this[LOCALS]; | 
|   }, | 
|   | 
|   set locals(val) { | 
|     if (!this[LOCALS_LIST]) { | 
|       this[LOCALS_LIST] = []; | 
|     } | 
|     this[LOCALS_LIST].push(val); | 
|   }, | 
|   | 
|   /** | 
|    * alias to {@link Context#locals}, compatible with koa that use this variable | 
|    * @member {Object} state | 
|    * @see Context#locals | 
|    */ | 
|   get state() { | 
|     return this.locals; | 
|   }, | 
|   | 
|   set state(val) { | 
|     this.locals = val; | 
|   }, | 
|   | 
|   /** | 
|    * Run async function in the background | 
|    * @param {Function} scope - the first args is ctx | 
|    * ```js | 
|    * this.body = 'hi'; | 
|    * | 
|    * this.runInBackground(async ctx => { | 
|    *   await ctx.mysql.query(sql); | 
|    *   await ctx.curl(url); | 
|    * }); | 
|    * ``` | 
|    */ | 
|   runInBackground(scope) { | 
|     // try to use custom function name first | 
|     /* istanbul ignore next */ | 
|     const taskName = scope._name || scope.name || eggUtils.getCalleeFromStack(true); | 
|     scope._name = taskName; | 
|     this._runInBackground(scope); | 
|   }, | 
|   | 
|   // let plugins or frameworks to reuse _runInBackground in some cases. | 
|   // e.g.: https://github.com/eggjs/egg-mock/pull/78 | 
|   _runInBackground(scope) { | 
|     const ctx = this; | 
|     const start = Date.now(); | 
|     /* istanbul ignore next */ | 
|     const taskName = scope._name || scope.name || eggUtils.getCalleeFromStack(true); | 
|     // use app.toAsyncFunction to support both generator function and async function | 
|     return ctx.app.toAsyncFunction(scope)(ctx) | 
|       .then(() => { | 
|         ctx.coreLogger.info('[egg:background] task:%s success (%dms)', taskName, Date.now() - start); | 
|       }) | 
|       .catch(err => { | 
|         // background task process log | 
|         ctx.coreLogger.info('[egg:background] task:%s fail (%dms)', taskName, Date.now() - start); | 
|   | 
|         // emit error when promise catch, and set err.runInBackground flag | 
|         err.runInBackground = true; | 
|         ctx.app.emit('error', err, ctx); | 
|       }); | 
|   }, | 
| }; | 
|   | 
| /** | 
|  * Context delegation. | 
|  */ | 
|   | 
| delegate(proto, 'request') | 
|   /** | 
|    * @member {Boolean} Context#acceptJSON | 
|    * @see Request#acceptJSON | 
|    * @since 1.0.0 | 
|    */ | 
|   .getter('acceptJSON') | 
|   /** | 
|    * @member {Array} Context#queries | 
|    * @see Request#queries | 
|    * @since 1.0.0 | 
|    */ | 
|   .getter('queries') | 
|   /** | 
|    * @member {Boolean} Context#accept | 
|    * @see Request#accept | 
|    * @since 1.0.0 | 
|    */ | 
|   .getter('accept') | 
|   /** | 
|    * @member {string} Context#ip | 
|    * @see Request#ip | 
|    * @since 1.0.0 | 
|    */ | 
|   .access('ip'); | 
|   | 
| delegate(proto, 'response') | 
|   /** | 
|    * @member {Number} Context#realStatus | 
|    * @see Response#realStatus | 
|    * @since 1.0.0 | 
|    */ | 
|   .access('realStatus'); |