'use strict'; // ////////////////////////////////////////////////////////////////////////////// // / DISCLAIMER // / // / Copyright 2013-2014 triAGENS GmbH, Cologne, Germany // / Copyright 2015-2016 ArangoDB GmbH, Cologne, Germany // / // / Licensed under the Apache License, Version 2.0 (the "License") // / you may not use this file except in compliance with the License. // / You may obtain a copy of the License at // / // / http://www.apache.org/licenses/LICENSE-2.0 // / // / Unless required by applicable law or agreed to in writing, software // / distributed under the License is distributed on an "AS IS" BASIS, // / WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // / See the License for the specific language governing permissions and // / limitations under the License. // / // / Copyright holder is ArangoDB GmbH, Cologne, Germany // / // / @author Dr. Frank Celler // / @author Alan Plum // ////////////////////////////////////////////////////////////////////////////// const _ = require('lodash'); const accepts = require('accepts'); const fs = require('fs'); const ansiHtml = require('ansi-html'); const dd = require('@arangodb/util').dedent; const arangodb = require('@arangodb'); const ArangoError = arangodb.ArangoError; const errors = arangodb.errors; const actions = require('@arangodb/actions'); const routeLegacyService = require('@arangodb/foxx/legacy/routing').routeService; const codeFrame = require('@arangodb/util').codeFrame; function solarize (ansiText) { try { ansiHtml.setColors({ reset: ['657b83', 'fdf6e3'], black: 'eee8d5', red: 'dc322f', green: '859900', yellow: 'b58900', blue: '268bd2', magenta: 'd33682', cyan: '2aa198', lightgrey: '586e75', darkgrey: '93a1a1' }); const html = ansiHtml(ansiText); return html; } finally { ansiHtml.reset(); } } function escapeHtml (raw) { return String(raw) .replace(/&/g, '&') .replace(/ ${escapeHtml(title || 'Service Unavailable')} ${body} `; } } }], middleware: [], context: {}, models: {}, foxx: true }; } // ////////////////////////////////////////////////////////////////////////////// // / @brief routes a default Configuration Required service // ////////////////////////////////////////////////////////////////////////////// function createServiceNeedsConfigurationRoute (service) { return createErrorRoute(service, new ArangoError({ errorNum: errors.ERROR_SERVICE_NEEDS_CONFIGURATION.code, errorMessage: errors.ERROR_SERVICE_NEEDS_CONFIGURATION.message }), dd`

Service needs to be configured

This service requires configuration and has either not yet been fully configured or is missing some of its dependencies.

`); } // ////////////////////////////////////////////////////////////////////////////// // / @brief routes this service if the original is broken service // ////////////////////////////////////////////////////////////////////////////// function createBrokenServiceRoute (service, err) { if (service.isDevelopment) { const title = String(err).replace(/\n/g, ' '); const frame = codeFrame(err.cause || err, service.basePath, true); let stacktrace = err.stack; while (err.cause) { err = err.cause; stacktrace += `\nvia ${err.stack}`; } const body = [ dd`

Failed to mount service at "${ escapeHtml(service.mount) }"

An error occurred while mounting this service.
This usually indicates a problem with the service itself.

`, frame ? dd`
        ${solarize(escapeHtml(frame))}
        
` : '', dd`

Stacktrace

        ${escapeHtml(stacktrace)}
        
` ].filter(Boolean).join('\n'); return createErrorRoute(service, err, body, title); } return createErrorRoute(service, err, dd`

Failed to mount service

An error occured while mounting the service.
Please check the log file for errors.

`); } function checkAndCreateDefaultDocumentRoute (service) { const defaultDocument = service.manifest.defaultDocument; if (defaultDocument) { service.routes.routes.push({ url: {match: '/'}, action: { do: '@arangodb/actions/redirectRequest', options: { permanently: false, destination: defaultDocument, relative: true } } }); } } // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- // ////////////////////////////////////////////////////////////////////////////// // / @brief computes the routes and exports of an service // ////////////////////////////////////////////////////////////////////////////// exports.routeService = function (service, throwOnErrors) { if (service.main.loaded && !service.isDevelopment) { return { exports: service.main.exports, routes: service.routes, docs: service.legacy ? null : service.docs }; } if (service.needsConfiguration()) { return { get exports () { if (!throwOnErrors) { return service.main.exports; } throw new ArangoError({ errorNum: errors.ERROR_SERVICE_NEEDS_CONFIGURATION.code, errorMessage: errors.ERROR_SERVICE_NEEDS_CONFIGURATION.message }); }, routes: createServiceNeedsConfigurationRoute(service), docs: null }; } service._reset(); let error = null; if (service.legacy) { error = routeLegacyService(service, throwOnErrors); checkAndCreateDefaultDocumentRoute(service); } else { checkAndCreateDefaultDocumentRoute(service); if (service.manifest.main) { try { service.main.exports = service.run(service.manifest.main); } catch (e) { e.codeFrame = codeFrame(e.cause || e, service.basePath); console.errorStack( e, `Service "${service.mount}" encountered an error while being mounted` ); if (throwOnErrors) { throw e; } error = e; } } service.buildRoutes(); } if (service.manifest.files) { const files = service.manifest.files; _.each(files, function (file, path) { const directory = file.path || file; const normalized = arangodb.normalizeURL(`/${path}`); const route = { url: {match: `${normalized}/*`}, action: { do: '@arangodb/actions/pathHandler', options: { root: service.root, path: fs.join(service.path, directory), type: file.type, gzip: Boolean(file.gzip) } } }; service.routes.routes.push(route); }); } service.main.loaded = true; return { exports: service.main.exports, routes: error ? createBrokenServiceRoute(service, error) : service.routes, docs: service.legacy ? null : service.docs }; };